Spring dependency injection not working with inheritance - java

I have a generic base dao class in which I implemented some generic methods for all daos.
<bean id="baseDAO" class="com.db.dao.BaseDao">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDAO" class="com.db.dao.UserDao"></bean>
<bean id="notesDAO" class="com.db.dao.NotesDao"></bean>
Initially, I was using the dependency injection to inject sessionFactory to every single dao, but later on I had implemented a base dao and had every other daos to extend this base dao.
However, after the change, whenever I call getSessionFactory() from one of the daos, I get null as return. The change makes sense to me but I cannot seem to figure out why it would return null since I've had the factorySession injected in the base.
BaseDao
public class BaseDao<T> {
private SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
...
}
UserDao
public class UserDao extends BaseDao<User> {
public User read(String userName) {
Session session = getSessionFactory().getCurrentSession();
session.beginTransaction();
...
}
...
}

The way i see it is that you forgot to add parent attribute on the children:
<bean id="baseDAO" class="com.db.dao.BaseDao" abstract="true">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="userDAO" class="com.db.dao.UserDao" parent="baseDAO"></bean>
<bean id="notesDAO" class="com.db.dao.NotesDao" parent="baseDAO"></bean>
I think its also a good idea if you mark the BaseDAO as abstract.

Related

JUNIT autowire datasource of DAOImpl extending NamedParameterJdbcDaoSupport

I have a Junit which somewhere down the line invokes a DaoImpl and this DaoImpl has a datasource attribute. Since this DaoImpl extends NamedParameterJdbcDaoSupport where setDataSource is marked final I cannot autowire a setter for this. My code (only when) invoked from a Junit fails with NPE at dataSource.getConnection() due to the dataSource attribute being null.
Here are the two things that I tried that works,
1> if I try below snippet and use this second attribute dataSource2.getConnection() in the called method it works just fine.
#Autowired
private DataSource dataSource;
#Autowired
private DataSource dataSource2;
#Autowired
public void setDataSource2(DataSource dataSource2){
this.dataSource2=dataSource2;
}
2> If I call parent getter directly while obtaining a connection within the called method it works just fine.
getDataSource.getConnection()
But it always fails if I use dataSource.getConnection() for below variations that I have tried,
#Autowired
private DataSource dataSource;
#Autowired
public void setDs(DataSource dataSource) {
this.dataSource = dataSource
}
OR
#Autowired
private DataSource dataSource;
#Autowired
private DataSource dataSource2;
#Autowired
public void setDataSource2(DataSource dataSource) {
this.dataSource2 = dataSource;
this.dataSource = dataSource;
}
I have also tried suggestion provided here,
#Autowired
private DataSource dataSource;
#PostConstruct
private void initialize() {
setDataSource(dataSource);
}
and here
#Autowired
public void setDs(DataSource dataSource) {
setDataSource(dataSource);
}
I can just go use getDataSource().getConnection() but this line dataSource.getConnection() is used in many places within the application and I cannot change it everywhere, that piece of code works just fine when deployed on JBOSS application server, just not via my Junit. Much appreciated if anyone point me what is going on here for the solutions that I tried and what I could do interms of Junit to fix this without having to change functional part of the code?
My junit class and application context looks as below:
public class MyTestC extends TestCase {
private ApplicationContext context;
public void setContext(ApplicationContext context) {
this.context = context;
}
private AToolController aToolController;
public void setUp() throws NamingException {
context = new ClassPathXmlApplicationContext("classpath:MyTestC.xml");
aToolController = (AToolController) context.getBean("AToolController");
}
#Test
public final void testDoSomething() throws AppException {
//aToolController.invokeSomething();
}
}
Context xml:
<bean id="jdbcTemplate"
class="org.springframework.jdbc.core.JdbcTemplate"
scope="prototype">
<constructor-arg><ref bean="datasource"/></constructor-arg>
</bean>
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>classpath:mytest.properties</value>
</property>
</bean>
<bean id="datasource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${mytest.jdbc.driverClassName}"></property>
<property name="url" value="${mytest.jdbc.url}"></property>
<property name="username" value="${mytest.jdbc.userName}"></property>
<property name="password" value="${mytest.jdbc.password}"></property>
</bean>
<bean id="ptDAO" class="com.ctl.abc.def.ghi.dao.AToolDAOImpl">
<property name="dataSource" ref="datasource"></property>
</bean>
<bean id="ptService" class="com.ctl.abc.def.ghi.service.AToolService">
<property name="ptDAO" ref="ptDAO"></property>
</bean>
<bean id="AToolController" class="com.ctl.abc.def.ghi.AToolController">
<property name="ptService" ref="ptService"></property>
</bean>

spring mvc + hibernate: createSQLQuery is not valid without active transaction

The old version of my code:
Session session = sessionFactory.openSession();
Query query = session.createQuery("From User");
List<Users> users = query.list();
session.close();
I config the hibernate.cfg.xml fileļ¼š
<property name="hibernate.current_session_context_class" > thread</property >
context.xml
<tx:annotation-driven transaction-manager="transactionManager"/>
Current code:
Session session = sessionFactory.getCurrentSession();
Transaction tx = session.beginTransaction();
Query query = session.createQuery("From User");
List<Users> list = query.list();
tx.commit();
I have to add Transaction code, or I will get an error
org.hibernate.HibernateException: createQuery is not valid without active transaction
What am I missing for the config?
ApplicationContext.xml
<?xml version='1.0' encoding='UTF-8' ?>
......
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" >
<property name="configLocation" value="classpath:hibernate.cfg.xml"></property>
</bean>
<context:annotation-config />
<context:component-scan base-package="*" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
</beans>
public class IndexController {
#Autowired
UserService users;
#RequestMapping("/index")
public String index(ModelMap model ) {
User user= users.test();
model.put("user", user);
return "index";
}
As suggested #eg04lt3r you don't need this line in the hibernate.cfg.xml
<property name="hibernate.current_session_context_class">thread</property>
You need to configure your spring context properly.
For the session factory, if you have mapping and properties in hibernate.cfg.xml and hibernate.properties
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean" />
for a transaction management
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
In a class that works with a session
public class Service {
#Autowired
private SessionFactory sessionFactory;
#Transactional
public List<User> list() {
Session session = sessionFactory.getCurrentSession();
Query query = session.createQuery("from User");
return (List<User>) query.list();
}
}
You can't get users by this way of course
new Service().list()
You need to get Service from the spring context. Spring will set sessionFactory in the Service and return a proxy for Service. When you call list() a proxy open a session and create a transaction.
Update
I reproduce your problem. With this classes everything works fine
public interface TextService {
public void save();
public List<SingleText> test();
}
#Service
public class TextServiceImpl implements TextService {
#Autowired
private SessionFactory sessionFactory;
#Override
#Transactional
public void save() {
SingleText text = new SingleText();
text.setTestText("S.Grey");
Session session = sessionFactory.getCurrentSession();
session.save(text);
}
#Override
#Transactional
public List<SingleText> test() {
Session session = sessionFactory.getCurrentSession();
return session.createCriteria(SingleText.class).list();
}
}
Without the #Transactional annotation I got
org.hibernate.HibernateException: No Session found for current thread
or (it depends of the Spring version)
org.hibernate.HibernateException: Could not obtain transaction-synchronized Session for current thread
So you just need the #Transaction annotation. And you don't need this
<property name="hibernate.current_session_context_class">thread</property>
Just remove this property if you do not use JTA. Spring do management transaction by default.
And define transaction manager in spring configuration:
<bean id = "transactionManager" class = "org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>

Spring Annotation : Converting XML Configuration to Annotation

I am using xml configuration in my Spring Application. Now i would like to convert the existing classes to use annotation(like #service, #Repository etc) instead of xml configuration.
Business Logic(Irrelevant for this question, just for understanding):
Sevice connnects to Americas database and find the skus(products) and deactivates the skus.
Sevice connnects to EMEA database and find the skus(products) and deactivates the skus.
Here is the sample code.
/* Service code, which has 2 instances of SkuDAO, one connecting to US database and one connecting to EMEA database */
public class DeactivationService {
private static final Logger LOG = Logger.getLogger(DeactivationService.class);
private SkuDAO amerdao; //Dependency Injection Amer
private SkuDAO emeadao; //Dependency Injection EMEA
public DeactivationService(SkuDAO amerdao,SkuDAO emeadao) {
this.amerdao=amerdao;
this.emeadao=emeadao;
}
/*
* Step 1: find inactive sku in americas skudao1.find()
* Step 2: find inactive sku in emea skudao2.find()
* Step 3: deactivate sku in americas
* Step 4: deactivate sku in emea
*/
public void deactivateSku() {
List<Sku> totalList = new ArrayList<Sku>();
List<Sku> amerList = amerdao.find();
List<Sku> emeaList = emeadao.find();
amerdao.deactivate(amerList);
emeaList.deactivate(emeaList);
}
}
/* DAO interface */
public interface SkuDAO {
public List<Sku> find();
public void deactivate(List<Sku>);
}
/* DAO Implementation
Here one constructor in which DataSource is injected
*/
public class SkuDAOImpl implements SkuDAO {
private DataSource datasource; //Dependency injection
private JdbcTemplate jdbcTemplate;
public SkuDAOImpl(DataSource datasource) {
this.datasource=datasource;
}
public List<Sku> find() {
//some processing to find the sku, purposely left empty as it is a sample code
}
public void deactivate(List<Sku>) {
//some processing to deactivate the sku, purposely left empty as it is a sample code
}
}
Spring Configuration:
<?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-3.0.xsd">
<context:property-placeholder location="file:${dbconfiguration}"/>
<bean id="AmericasDataSource" class="dell.harmony.data.HarmonyBasicDataSource" destroy-method="close" >
<property name="url"><value>${HarmonyAmericasDb.url}</value></property>
<property name="driverClassName"><value>${HarmonyAmericasDb.driverClassName}</value></property>
<property name="username"><value>${HarmonyAmericasDb.username}</value></property>
<property name="password"><value>${HarmonyAmericasDb.password}</value></property>
<property name="initialSize"><value>${HarmonyAmericasDb.initialSize}</value></property>
<property name="maxActive"><value>${HarmonyAmericasDb.maxActive}</value></property>
<property name="maxWait"><value>${HarmonyAmericasDb.maxWait}</value></property>
<property name="maxIdle"><value>${HarmonyAmericasDb.maxIdle}</value></property>
<property name="minIdle"><value>${HarmonyAmericasDb.minIdle}</value></property>
<property name="removeAbandoned"><value>${HarmonyAmericasDb.removeAbandoned}</value></property>
<property name="removeAbandonedTimeout"><value>${HarmonyAmericasDb.removeAbandonedTimeout}</value></property>
</bean>
<bean id="EMEADataSource" class="dell.harmony.data.HarmonyBasicDataSource" destroy-method="close" >
<property name="url"><value>${HarmonyEMEADb.url}</value></property>
<property name="driverClassName"><value>${HarmonyEMEADb.driverClassName}</value></property>
<property name="username"><value>${HarmonyEMEADb.username}</value></property>
<property name="password"><value>${HarmonyEMEADb.password}</value></property>
<property name="initialSize"><value>${HarmonyEMEADb.initialSize}</value></property>
<property name="maxActive"><value>${HarmonyEMEADb.maxActive}</value></property>
<property name="maxWait"><value>${HarmonyEMEADb.maxWait}</value></property>
<property name="maxIdle"><value>${HarmonyEMEADb.maxIdle}</value></property>
<property name="minIdle"><value>${HarmonyEMEADb.minIdle}</value></property>
<property name="removeAbandoned"><value>${HarmonyEMEADb.removeAbandoned}</value></property>
<property name="removeAbandonedTimeout"><value>${HarmonyEMEADb.removeAbandonedTimeout}</value></property>
</bean>
**<!-- Sku Deactivation -->**
<bean id="SkuAmerDao" class="dell.harmony.service.skudeactivation.dao.SkuDAOImpl">
<constructor-arg index="0"><ref bean="AmericasDataSource"/></constructor-arg>
</bean>
<bean id="SkuEMEADao" class="dell.harmony.service.skudeactivation.dao.SkuDAOImpl">
<constructor-arg index="0"><ref bean="EMEADataSource"/></constructor-arg>
</bean>
<bean id="ServiceManager" class="dell.harmony.service.skudeactivation.service.DeactivationService">
<constructor-arg index="0"><ref bean="SkuAmerDao"/></constructor-arg>
<constructor-arg index="1"><ref bean="SkuEMEADao"/></constructor-arg>
</bean>
</beans>
Now i want to convert the above classes to highlighted inside xml("Sku Deactivation") , into annodation.
My code for convertion is as follows:
#Service
public class DeactivationService {
private static final Logger LOG = Logger.getLogger(DeactivationService.class);
private SkuDAO amerdao; //Dependency Injection Amer
private SkuDAO emeadao; //Dependency Injection EMEA
#Autowired(required=true)
public DeactivationService( #Qualifier("SkuAmerDao") SkuDAO amerdao, #Qualifier("SkuEMEADao") SkuDAO emeadao) {
this.amerdao=amerdao;
this.emeadao=emeadao;
}
}
In the above constructor, now 'amerdao' instance, should be injected with AmericasDataSource and 'emeadao' with EMEADataSource, how to do that?
Please note, i dont have a setter in the SkuDAOImpl. Also there is only one datasource instance inside the SkuDAOImpl.
can you given sample code of SkuDAOImpl with annodation.
Any suggestion, to improve the coding from service to dao , if it can be done in a better way. (Not required to answer this)
EDITED NOW: just to be clear with question 1, I would like to remove the below two lines in Spring xml and use annotation instead my DeactivationService. Is it possible?
<bean id="SkuAmerDao" class="dell.harmony.service.skudeactivation.dao.SkuDAOImpl">
<constructor-arg index="0"><ref bean="AmericasDataSource"/></constructor-arg>
</bean>
<bean id="SkuEMEADao" class="dell.harmony.service.skudeactivation.dao.SkuDAOImpl">
<constructor-arg index="0"><ref bean="EMEADataSource"/></constructor-arg>
</bean>
What about:
#Service
public class DeactivationService {
private static final Logger LOG = Logger.getLogger(DeactivationService.class);
#Autowired
#Qualifier("SkuAmerDao")
private SkuDAO amerdao; //Dependency Injection Amer
#Autowired
#Qualifier("SkuEMEADao")
private SkuDAO emeadao; //Dependency Injection EMEA
// no constructor needed.
}
public abstract class BaseDao implements SkuDAO {
private final JdbcTemplate jdbcTemplate;
protected BaseDao() {
this.jdbcTemplate = new JdbcTemplate(getDataSource());
}
protected abstract DataSource getDataSource();
public List<Sku> find() {
//some processing to find the sku, purposely left empty as it is a sample code
}
public void deactivate(List<Sku>) {
//some processing to deactivate the sku, purposely left empty as it is a sample code
}
}
#Repository("SkuAmerDao")
public class SkuAmerDAOImpl extends BaseDao {
#Autowired
#Qualifier("AmericasDataSource")
private DataSource datasource; //Dependency injection
#Override
protected DataSource getDatasource() {
return dataSource;
}
}
#Repository("SkuEMEADao")
public class SkuEMEADAOImpl extends BaseDao {
#Autowired
#Qualifier("EMEADataSource")
private DataSource datasource; //Dependency injection
#Override
protected DataSource getDatasource() {
return dataSource;
}
}
Always the same principle:
class is made a bean by an annotation #Service, #Component, #Repository (those annotations can take the name of the bean as value)
injection of dependency is made on fields with #Autowired and if there are more than one corresponding bean (in your case you have two DataSources), add a #Qualifier to specify which one.
Full documentation here.

How to handle cyclic dependency in spring

For example i have two beans:
class Bean1 {
private SomeService service1;
private SomeService servive2;
private Bean2 bean2;
public void doStuff() {
service1.doActualStuff();
}
public void setBean2(Bean2 bean2) {
this.bean2 = bean2;
}
public Bean2 getBean2() { return this.bean2 }
}
class Bean2 {
private Bean1 bean1;
private SomeService3 service3;
public void init() {
bean1.doStuff();
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
}
}
Now if i try to configure them in spring in the folllowing way:
<bean id="service1" class="SomeService">
...
</bean>
<bean id="bean1" class="Bean1">
<property name="bean2" ref="bean2"/>
<property name="service1" ref="service1"/>
...
</bean>
<bean id="bean2" class="Bean2" init-method="init">
<property name="bean1" ref="bean1"/>
...
</bean>
Init method of bean2 is executed. Bean2 has injected bean1, but bean1 itself is not fully initialized so calling bean1.doStuff() that will call service1.doActualStuff() will return into NPE. Why bean1 is not fully initialized?
Spring caches singleton beans in a not-fully-initialized state for injection into places that would otherwise be an unresolvable circular reference. In your case, the initialization order would be something like this:
Instantiate bean1 (meaning call the constructor only, not init methods)
Add bean1 to the singleton cache to handle circular dependencies
Start injecting bean1's dependencies
Instantiate bean2 to satisfy bean1's dependency
Add bean2 to the singelton cache to handle circular dependencies
Start injecting bean2's dependencies--one of these is the cached bean1 instance, which is still not fully initialized
Finish injecting bean2's dependencies
Call bean2's init method--uhoh! bean1 still isn't initted yet!
Done creating bean2
(If you actually made it this far...) Finish injecting bean1's dependencies
No init method on bean1, but this is where it would be called
Done creating bean1
Consider rethinking your design to untangle the dependencies between bean1 and bean2.
How about if you inject the first bean programatically:
class Bean2 {
private Bean1 bean1;
private SomeService3 service3;
public void init() {
bean1.doStuff();
}
public void setBean1(Bean1 bean1) {
this.bean1 = bean1;
//HERE
this.bean1.setBean2(this);
}
}
Remove the first injection from your spring xml:
<bean id="service1" class="SomeService">
...
</bean>
<bean id="bean1" class="Bean1">
<!-- NOT NEEDED ANYMORE <property name="bean2" ref="bean2"/> -->
<property name="service1" ref="service1"/>
...
</bean>
<bean id="bean2" class="Bean2" init-method="init">
<property name="bean1" ref="bean1"/>
...
</bean>

UserDao is null, I am wiring the bean wrong and need help

My homecontroller has a UserService object that gets wired using spring correctly (it renders the index page just fine using a method no UserService).
Now I setup hibernate, so inside UserService I have a UserDao object that I am trying to wire using spring.
#Service
public class UserServiceImpl implements UserService{
UserDao userDao;
public String sayHello() {
return "hello from user service impl part 2";
}
public String getTestUser() {
return userDao.getById(1L).getUsername();
}
}
So my HomeController was calling the 'sayHello' method and it was working fine like I said.
#Controller
public class HomeController {
#Autowired
private UserService userService;
#RequestMapping("/")
public ModelAndView Index() {
ModelAndView mav = new ModelAndView();
mav.setViewName("index");
mav.addObject("message", userService.sayHello());
mav.addObject("username", userService.getTestUser());
//userService.getTestUser();
return mav;
}
The call to userService.getTestUser() fails, as the UserDao is null.
My app-config.xml is:
<!-- Hibernate SessionFactory -->
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<!--<property name="packagesToScan" value="com.blah.core.db.hibernate"/> -->
<property name="configLocation" value="/WEB-INF/classes/hibernate.cfg.xml"/>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
hibernate.connection.url=jdbc:mysql://localhost/blah
hibernate.connection.username=dbuser
hibernate.connection.password=123
hibernate.query.substitutions=true 'Y', false 'N'
hibernate.cache.use_query_cache=true
hibernate.cache.use_second_level_cache=true
hibernate.cache.provider_class=org.hibernate.cache.EhCacheProvider
hibernate.jdbc.batch_size=0
</value>
</property>
</bean>
<!-- Transaction manager for a single Hibernate SessionFactory (alternative to JTA) -->
<bean id="userDao" class="com.blah.core.db.hibernate.UserDaoImpl">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
Why is my UserDao null? I must be doing something wrong with the wiring?
Also, if I uncomment out the name=packagesToScan line, do I really need to define a bean for each Dao like I did with UserDao? Will the sessionFactory get wired somehow?
Add #AutoWired annotation to userDao.
#Service
public class UserServiceImpl implements UserService{
#AutoWired
UserDao userDao;
...
}
And make sure you have set up <context:component-scan/> to scan the packages that your #Services and #Controllers are in.
As krock mentioned, your UserDao is not being "wired" properly inside your UserService. Did you even try his suggestion ?

Categories

Resources