I am having some trouble with setting up my Spring environment properly. In my applicationContext.xml I have:
...
<context:annotation-config />
<context:component-scan base-package="com.company.server" />
<import resource="databaseConfig.xml" />
<bean id="propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:config.properties</value>
</list>
</property>
</bean>
and in my databaseConfig:
<tx:annotation-driven />
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass">
<value>${jdbc.driver.className}</value>
</property>
<property name="jdbcUrl">
<value>${jdbc.url}</value>
</property>
<property name="user">
<value>${jdbc.username}</value>
</property>
<property name="password">
<value>${jdbc.password}</value>
</property>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource">
<ref bean="dataSource" />
</property>
<property name="packagesToScan" value="org.adit.spring.hibernate.entity" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">false</prop>
</props>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory">
<ref bean="sessionFactory" />
</property>
</bean>
Now my problem starts. If you look at the following class:
#Service
public class ViewContactsServiceImpl extends RemoteServiceServlet implements ViewContactsService {
private ContactDao contactDao;
#Autowired
public void setContactDao(ContactDao contactDao) {
this.contactDao = contactDao;
}
#Override
public ArrayList<Contact> getAllContacts() {
return contactDao.getAllContacts();
}
}
During application startup everything is fine. Spring does not complain that it cannot create the bean or that it cannot inject the property. However, whenever I try to access the contactDao field, it is null.
Thanks!
UPDATE
I should also mention my ContactDaoImpl.java is defined as:
#Repository("contactDao")
#Transactional
public class ContactDaoImpl implements ContactDao { ... }
UPDATE 2
NB. This is a GWT application.
ViewContactServiceImpl.java:
package com.company.server.service.viewcontacts;
ViewContactsService.java:
package com.company.client.viewcontacts;
ContactDaoImpl.java
package com.company.server.contact;
ContactDao.java
package com.company.server.contact;
I thins ViewContactsServiceImpl is being instantiated by GWT (guessing based on RemoteServiceServlet) - so it is not spring managed bean.
You need to invoked auto-wire manually by overriding and implementing the init method. Similar to the code shown below (from this article). As explained in that article create an AbstractRemoteServlet that all your GWTService can extend.
#Override
public void init(ServletConfig config) throws ServletException {
super.init(config);
WebApplicationContext ctx = WebApplicationContextUtils
.getRequiredWebApplicationContext(config.getServletContext());
AutowireCapableBeanFactory beanFactory = ctx
.getAutowireCapableBeanFactory();
beanFactory.autowireBean(this);
}
Look at GWT-SL library for another approach to exposing spring managed beans as GWT remote services.
Related
I'm using hibernate integrated with Spring annotation and getting FileNotFoundException for my Entity class
This is my applicationContext.xml
<?xml version='1.0' encoding='UTF-8'?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:p="http://www.springframework.org/schema/p"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd">
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
<property name="url" value="jdbc:mysql://localhost:3306/db1"></property>
<property name="username" value="root"></property>
<property name="password" value="root"></property>
</bean>
<bean id="mysessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="mappingResources">
<list>
<value>vendors.Vendor</value>
<value>accountBooks.DayBookData</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="template" class="org.springframework.orm.hibernate3.HibernateTemplate">
<property name="sessionFactory" ref="mysessionFactory"></property>
</bean>
<bean id="vendor" class="vendors.VendorDao">
<property name="hibernateTemplate" ref="template"></property>
</bean>
<bean id="dayBook" class="accountBooks.DayBookDao">
<property name="hibernateTemplate" ref="template"></property>
</bean>
</beans>
My Dao class
public class DayBookDao {
private HibernateTemplate hibernateTemplate;
public void setHibernateTemplate(HibernateTemplate hibernateTemplate) {
this.hibernateTemplate = hibernateTemplate;
}
public void saveDayBookData(DayBookData dayBook){
hibernateTemplate.save(dayBook);
}
public void updateDayBookData(DayBookData dayBook){
hibernateTemplate.update(dayBook);
}
public void deleteDayBookData(DayBookData dayBook){
hibernateTemplate.delete(dayBook);
}
public List<DayBookData> getDayBookData(){
List<DayBookData> dayBook = hibernateTemplate.loadAll(DayBookData.class);
return dayBook;
}
}
My Main class
public static void main(String[] args) {
// TODO Auto-generated method stub
Resource r = new ClassPathResource("applicationContext.xml");
BeanFactory bean = new XmlBeanFactory(r);
DayBookDao dayBookDao = (DayBookDao) bean.getBean("dayBook");
DayBookData dayBook = new DayBookData();
dayBook.setAccountType("Bank Account");
dayBook.setTransType("Receipt");
dayBook.setOppAccount("Profit-Loss");
dayBook.setAmount(15000);
dayBook.setTransDate(new Date());
dayBookDao.saveDayBookData(dayBook);
}
I'm getting error
**Caused by: java.io.FileNotFoundException: class path resource [vendors.Vendor] cannot be opened because it does not exist
Property mappingResources are used for XML (hbm.xml) mapping.
Hibernae 4 and above
You just need to put all your persistent classes to the some.package.model package and use
<property name="packagesToScan" value="some.package.model" />
to add all classes from that package. Inner packages are processed as well.
Also you can add persistent classes separately using
<property name="annotatedClasses">
<list>
<value>vendors.Vendor</value>
<value>accountBooks.DayBookData</value>
</list>
</property>
Hibernate 3
Hibearnate 3 configuration using annotated persistent classes and Spring a bit more complex.
It is need to add persistent classes to the hibernate.cfg.xml and configure Spring by this way:
<bean id="mysessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="configLocation">
<value>classpath:hibernate.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
</bean>
Hibernate 3 uses a separate config class for configurations with annotations:
org.hibernate.cfg.AnnotationConfiguration
I have a controller where I autowire repository:
#Controller
#RequestMapping("/account")
#EnableJpaRepositories
public class AccountController {
#Autowired
private AccountRepository accountRepo;
//methods
}
My repository extends CrudRepository
#Repository
public interface AccountRepository extends CrudRepository<Account, Integer> {
Account findOne(int primaryKey);
}
I use xml to configure my project. Here it is:
<jpa:repositories base-package="com.library.repositories"
entity-manager-factory-ref="entityManager"></jpa:repositories>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManager" />
</bean>
<bean id="entityManager"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.library.entities" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" />
</property>
<property name="jpaProperties">
<props>
<!-- <prop key="hibernate.hbm2ddl.auto">create-drop</prop> -->
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/library" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
Why it doesn't work? The error I receive is that AccountController cannot autowire bean AccountRepository.
EDIT
I've refactored my configuration to annotation based and everything works. In my XML version I probably didn't scan some classes and it resulted with error.
May be you need to have #EnableJpaRepositories annotation on a configuration class with #Configuration annotation instead of Controller class.
Also, make sure your Configuration classes are under a scanned package.
Hi i'm trying to save into two database simultaneously but I always get an error.
Exception in thread "main" org.hibernate.HibernateException: No Session found for current thread
here's my code :
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW, readOnly=false)
public void save(ArsenalPlayer domain1, ArsenalPlayer2 domain2)
throws Exception {
dao1.save(domain1);
dao2.save(domain2);
}
dao1 uses a sessionFactory attached to datasource1
dao2 uses a sessionFactory attached to datasource2
and here's my configuration
DataSource
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/arsenal" />
<property name="user" value="root" />
<property name="password" value="ahmids" />
</bean>
SessionFactory
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">update</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.gongfu4.bean.ArsenalPlayer</value>
</list>
</property>
</bean>
DataSource2
<bean id="dataSource2" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost:3306/arsenal2" />
<property name="user" value="root" />
<property name="password" value="ahmids" />
</bean>
SessionFactory2
<bean id="sessionFactory2"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource2" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">update</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<!-- <prop key="hibernate.current_session_context_class">thread</prop> -->
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.gongfu4.bean.ArsenalPlayer2</value>
</list>
</property>
</bean>
applicationContext
<context:component-scan base-package="com.gongfu4" />
<context:annotation-config />
<import resource="dataSource.xml" />
<import resource="dataSource2.xml" />
<import resource="hibernate.xml" />
<import resource="hibernate2.xml" />
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean id="myTx"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
and here are my dao classes :
DAO1
#Autowired
SessionFactory sessionFactory;
public void save(ArsenalPlayer domain) {
sessionFactory.getCurrentSession().save(domain);
}
DAO2
#Autowired
SessionFactory sessionFactory2;
public void save(ArsenalPlayer2 domain) {
sessionFactory2.getCurrentSession().merge(domain);
}
Is there something wrong with my configuration?
You cannot use those two transaction managers like that. You have two data sources, two transaction managers and, from your code, I understand that you want the two save operations to be performed in the same transaction. The question is "a transaction from which transaction manager?".
The way you have the code and the configuration, Spring will use the "default" transaction manager because <tx:annotation-driven/> by default will search for a transaction manager bean with the id "transactionManager" and the bean with this id is the one for data source dataSource. But your code is not working and this is the expected behavior. Spring will open a Hibernate session using sessionFactory and the dao1.save(domain1); call will succeed because this is the correct Hibernate session for the correct dataSource. But when the dao2.save(domain2); method is called you will have the same session from dao1 call but be used for a db operation for the second database.
As I see it you have two options:
Use a JTA transaction manager to coordinate the two datasources. With a JTA the two save operations will be atomic. If one fails, then both are rolled back.
Perform the two save(domain) operations in two different transactions properly configuring the #Transactional annotation to use the correct transaction manager. In this case, the two save operations will not be atomic. If one save fails then only that one will be rolled-back. See below an exempt taken from the Spring reference documentation here:
public class TransactionalService {
#Transactional("order")
public void setSomething(String name) { ... }
#Transactional("account")
public void doSomething() { ... }
}
<tx:annotation-driven/>
<bean id="transactionManager1" class="org.springframework.jdbc.DataSourceTransactionManager">
...
<qualifier value="order"/>
</bean>
<bean id="transactionManager2" class="org.springframework.jdbc.DataSourceTransactionManager">
...
<qualifier value="account"/>
</bean>
Your current configuration doesn't support global transactions (XA) and therefore you can't span one Transaction on two different databases.
For this reason you need two Hiberante transaction managers, one for each session factory. Then you need to instruct the transactional service which transaction manager should be used.
So instead of:
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW, readOnly=false)
public void save(ArsenalPlayer domain1, ArsenalPlayer2 domain2)
throws Exception {
dao1.save(domain1);
dao2.save(domain2);
}
you should have:
<bean id="txManager1" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory1" />
</bean>
<bean id="txManager2" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory2" />
</bean>
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW, readOnly=false, value="txManager1")
public void save(ArsenalPlayer domain1)
throws Exception {
dao1.save(domain1);
}
#Transactional(rollbackFor=Exception.class, propagation=Propagation.REQUIRES_NEW, readOnly=false, value="txManager2")
public void save(ArsenalPlayer domain2)
throws Exception {
dao2.save(domain2);
}
I just created two small crud applications one is a web application and the other I am running from a main method.
I am confused about how the sessionFactory object is being obtained in both the applications.
In my web application in DAOImpl I am just injecting the sessionFactory object and doing
#Repository
public class ContactDaoImpl implements ContactDao {
#Autowired
private SessionFactory sessionFactory;
public void addContact(Contact contact) {
//save: Persist the given transient instance
sessionFactory.getCurrentSession().save(contact);
}
My Spring Application Context
<!-- <context:property-placeholder> XML element automatically registers a new PropertyPlaceholderConfigurer
bean in the Spring Context. -->
<context:property-placeholder location="classpath:database.properties" />
<context:component-scan base-package="com.contactmanager"/>
<!-- enable the configuration of transactional behavior based on annotations -->
<tx:annotation-driven transaction-manager="hibernateTransactionManager"/>
<!-- View Resolver Configured -->
<bean id="viewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix">
<value>/WEB-INF/views/</value>
</property>
<property name="suffix">
<value>.jsp</value>
</property>
</bean>
<!-- Creating DataSource -->
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${database.driver}" />
<property name="url" value="${database.url}" />
<property name="username" value="${database.user}" />
<property name="password" value="${database.password}" />
</bean>
<!-- To persist the object to database, the instance of SessionFactory interface is created.
SessionFactory is a singleton instance which implements Factory design pattern.
SessionFactory loads hibernate.cfg.xml and with the help of TransactionFactory and ConnectionProvider
implements all the configuration settings on a database. -->
<!-- Configuring SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.contactmanager.model.Contact</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
<!-- Configuring Hibernate Transaction Manager -->
<bean id="hibernateTransactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
But in the other application In which I don't use Spring I only use hibernate. I have to get the sessionFactory from annotationConfiguration then open the session and begin transaction.
AnnotationConfiguration().configure().buildSessionFactory();
Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
Stock stock = new Stock();
stock.setStockCode("4715");
stock.setStockName("GENM");
session.save(stock);
session.getTransaction().commit();
Can anyone tell me why I do have to written more lines of code to persist an object here. Is the Spring configuration doing everything in the first application?
This part of your Spring configuration is configuring the sessionFactory bean:
<!-- Configuring SessionFactory -->
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.contactmanager.model.Contact</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
</props>
</property>
</bean>
You can read more about setting up the Hibernate session factory with Spring here
This part of your DAO code is responsible for asking Spring to inject the session factory:
#Autowired
private SessionFactory sessionFactory;
You can read more about autowiring in Spring here
i have a simple question. Its possible to add dependency injection via #Ressource or #Autowired to the Hibernate Eventlistener?
I will show you my entitymanagerfactory configuration:
<bean id="entityManagerFactory" class="org.hibernate.ejb.EntityManagerFactoryImpl">
<qualifier value="entityManagerFactory" />
<constructor-arg>
<bean
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitManager">
<bean
class="org.springframework.orm.jpa.persistenceunit.DefaultPersistenceUnitManagerr">
<property name="defaultDataSource" ref="dataSource" />
</bean>
</property>
<property name="dataSource" ref="dataSource" />
<property name="persistenceUnitName" value="mis" />
<property name="persistenceProviderClass" value="org.hibernate.ejb.HibernatePersistence" />
<property name="jpaProperties" ref="jpa.properties" />
<property name="jpaDialect" ref="jpaDialect" />
<property name="jpaVendorAdapter">
<bean
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="database">
<util:constant
static-field="org.springframework.orm.jpa.vendor.Database.POSTGRESQL" />
</property>
<property name="showSql" value="true" />
</bean>
</property>
</bean>
</constructor-arg>
</bean>
At the moment i register my listener via jpa.properties,
hibernate.ejb.event.load=com.example.hibernate.events.LoadEvent
but in this case i have no spring injection in my listener. I found a solution, but this use the sessionFactory and not the entitymanager oder can i modifiy the sessionfactory in my context? Hopefully someone have a nice idea or solutionhow to deal with this problematic!
Big thanks!
If you used SessionFactory, this would be the configuration:
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<!-- Stripped other stuff -->
<property name="eventListeners">
<map>
<entry key="pre-load">
<bean class="com.mycompany.MyCustomHibernateEventListener1" />
</entry>
<entry key="pre-persist">
<bean class="com.mycompany.MyCustomHibernateEventListener2" />
</entry>
</map>
</property>
</bean>
But since you are using JPA, I'm afraid you need to use AOP as outlined in this thread
Or you can
store the ApplicationContext in a ThreadLocal or a custom holder class and expose it through a static method
have a base class for your listeners something like this:
Base class:
public abstract class ListenerBase{
protected void wireMe(){
ApplicationContext ctx = ContextHelper.getCurrentApplicationContext();
ctx.getAutowireCapableBeanFactory().autowireBean(this);
}
}
Now in your lifycycle methods call wireMe() first.
Update:
Here is a sample implementation of ContextHelper:
public final class ContextHelper implements ApplicationContextAware{
private static final ContextHelper INSTANCE = new ContextHelper();
private ApplicationContext applicationContext;
#Override
public void setApplicationContext(final ApplicationContext applicationContext){
this.applicationContext = applicationContext;
}
public static ApplicationContext getCurrentApplicationContext(){
return INSTANCE.applicationContext;
};
public static ContextHelper getInstance(){
return INSTANCE;
}
private ContextHelper(){
}
}
Wire it in your Spring Bean configuration like this:
<bean class="com.mycompany.ContextHelper" factory-method="getInstance" />