I have a dao package where all my DaoClasses implements amongst others the following methode:
public class XDaoImpl implements XDao {
private SessionFactory sessionFactory;
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory() {
return sessionFactory;
}
#Override
public void saveOrUpdate(MyObject o) {
//Transaction trans = getSessionFactory().getCurrentSession().beginTransaction();
getSessionFactory().getCurrentSession().saveOrUpdate(o);
//trans.commit();
}
}
If I run my application it needs a lot time to store my objects to the database. I belief it happens because I create a new Transaction for each object. So I tried to use Spring Frameworkâs xml based declarative transaction implementation. But till now it does not work for me:
<beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>/resources/spring/config/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>
<bean id="hibernate3SessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list>
<value>/resources/spring/config/A.hbm.xml</value>
<value>/resources/spring/config/B.hbm.xml</value>
<value>/resources/spring/config/C.hbm.xml</value>
<value>/resources/spring/config/D.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.PostgreSQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="dBo" class="com.model.bo.DBoImpl">
<property name="dDao" ref="dDao" />
<property name="bDao" ref="bDao" />
</bean>
<bean id="dDao" class="com.model.dao.dDaoImpl">
<property name="sessionFactory" ref="hibernate3SessionFactory" />
</bean>
<bean id="aBo" class="com.model.bo.aBoImpl">
<property name="aDao" ref="aDao" />
<property name="bDao" ref="bDao" />
<property name="cDao" ref="cDao" />
</bean>
<bean id="bDao" class="com.model.dao.bDaoImpl">
<property name="sessionFactory" ref="hibernate3SessionFactory" />
</bean>
<bean id="cDao" class="com.model.dao.cDaoImpl">
<property name="sessionFactory" ref="hibernate3SessionFactory" />
</bean>
<bean id="aDao" class="com.model.dao.aDaoImpl">
<property name="sessionFactory" ref="hibernate3SessionFactory" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="hibernate3SessionFactory" />
</bean>
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="get*" read-only="true" />
<tx:method name="*" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="boMethods" expression="execution(* com.model.bo.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="boMethods" />
</aop:config>
</beans>
The error that is thrown:
class org.springframework.beans.factory.BeanCreationException Error
creating bean with name 'dataSource' defined in class path resource
[resources/spring/config/BeanLocations.xml]: BeanPostProcessor before
instantiation of bean failed; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name
'org.springframework.aop.support.DefaultBeanFactoryPointcutAdvisor#0':
Cannot resolve reference to bean 'boMethods' while setting bean
property 'pointcut'; nested exception is
org.springframework.beans.factory.BeanCreationException: Error
creating bean with name 'boMethods': Instantiation of bean failed;
nested exception is java.lang.NoClassDefFoundError:
org/aspectj/weaver/BCException
public class DBoImpl implements DBo {
private DDao dDao;
private BDao bDao;
public DDao getDDao() {
return dDao;
}
public void setDDao(DDao dDao) {
this.dDao = dDao;
}
public BDao getbDao() {
return bDao;
}
public void setbDao(BDao bDao) {
this.bDao = bDao;
}
public D add(D r) {
dDao.saveOrUpdate(r);
return r;
}
}
It looks like you don't have the AOP jar files in your class path.
See:
http://docs.spring.io/spring/docs/current/spring-framework-reference/html/aop.html
Look for the section "10.2.1 Enabling #AspectJ Support"
Using AOP for transactional behavior is fine. I'd suggest having a look at annotation based configuration (Note the <tx:annotation-driven transaction-manager="transactionManager" />), which might be a little bit more straightforward.
Furthermore I would be careful about using this configuration. A transaction is meant to encapsulate an atomic unit of work. Having a method like saveOrUpdate(EntityType entity) I'd think your atomic unit of work was saving one entity, not saving n entities. The longer a transaction runs, the greater gets the probability of running into deadlocks.
I'd suggest creating a Method like public void saveOrUpdateInBatch(MyObject... objects). The name implies you are dealing with an atomic operation which handles a number of elements. Also you might want to optimize this method for batch inserts.
Related
#Transactional is not working in spring mvc. suppose i removed
#Transactional annotation data is reached to RepositoryClass.
Throwable targetException - org.springframework.web.method.support.InvocableHandlerMethod.doInvoke(Object...)
i need to reach data to repository class.
please help me.,
Thank you.
ServiceImplClass
#Service("userService")
public class UserServiceImpl implements UserService{
#Autowired
UserRepository userRepository;
public String saveUserData(User user,HttpSession session) {
return userRepository.saveUserData(user);
}
}
RepositoryClass:
#Component
#Transactional
public class UserRepository {
#Autowired
protected SessionFactory sessionFactory;
public SessionFactory getSessionFactory() {
return sessionFactory;
}
public void setSessionFactory(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
public String saveUserData(User user) {
final Session session = (Session) getSessionFactory();
try {
session.beginTransaction();
Query query=session.createQuery("UPDATE User set user_Name =:userName,"
+ "reg_Date =:regDate,"
+ "img_Id=:imgId, emailId =:emailId");
query.setParameter("userName", user.getUserName());
query.setParameter("regDate", user.getRegDate());
query.setParameter("imgId", user.getImgId());
query.setParameter("emailId", user.getEmailId());
session.save(user);
session.getTransaction().commit();
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
}
dispatcher-servlet.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util" xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context-4.2.xsd
http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-4.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.2.xsd
">
<context:annotation-config />
<context:component-scan base-package="com.demo.app" />
<mvc:default-servlet-handler />
<mvc:annotation-driven>
<mvc:message-converters register-defaults="true">
<bean class="org.springframework.http.converter.StringHttpMessageConverter">
<property name="supportedMediaTypes" value="text/plain;charset=UTF-8" />
</bean>
</mvc:message-converters>
</mvc:annotation-driven>
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/html/" />
<property name="suffix" value="html" />
</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/UserDB" />
<property name="username" value="root" />
<property name="password" value="password" />
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>com.demo.app.model.User</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean
class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">
<property name="exceptionMappings">
<props>
<prop key="java.lang.Exception">Error</prop>
</props>
</property>
</bean>
<bean id="multipartResolver"
class="org.springframework.web.multipart.commons.CommonsMultipartResolver">
<property name="maxUploadSize" value="2097152" />
</bean>
</beans>
You're managing your transactions manually. That's the task of transaction manager. saveUserData should be like:
public User saveUserData(User user) {
return (User)sessionFactory.getCurrentSession().merge(user);
}
And that's it.
And you'll probably want to annotate your service with #Transactional and not repository.
Your Repository don`t use #component annotation. and you use
<jpa:repositories base-package="your.package.put.repository"></jpa:repositories>
so, you already used
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
First of all all transaction and session should managed by spring container is good practice so please don't manage session at your own, just use the existing session for data base querying. Now, for only your situation, try #Transactional annotation at Controller level and if it will work then you require some modification as per given below.
For web MVC Spring app should #Transactional go on controller or service?
Use #Transactional at Service level and when one of the operations doesnt work as it should(for example, an update operation returns 0 which means it failed) throw new RuntimeException(). If one of the operation fails, all other operations which are part of the transaction will be rolled back.
You are trying to use both container managed transaction and User managed transaction at the same time. Try to use only one at a time.
Either remove #Transactional annotation or remove the transaction statements from your method.
I have this maven project with its modules
Parent
|_____Model
|_____Persistence
|_ persistence-context.xml
|_____Service
|_ service-context.xml
|_____View
|_ spring/app-config.xml
And in persistence-context.xml have the next:
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"
default-autowire="byName">
<tx:annotation-driven transaction-manager="persistence.transactionManager" proxy-target-class="true" />
<bean id="persistence.propertyConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath*:META-INF/jdbc.properties</value>
<value>classpath*:META-INF/hibernate.properties</value>
</list>
</property>
</bean>
<bean id="persistence.transactionManager" class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="persistence.sessionFactory" />
<property name="jdbcExceptionTranslator" ref="persistence.jdbcExceptionTranslator" />
</bean>
<bean name="persistence.jdbcExceptionTranslator" class="org.springframework.jdbc.support.SQLErrorCodeSQLExceptionTranslator">
<constructor-arg>
<ref bean="persistence.dataSource" />
</constructor-arg>
</bean>
<bean id="persistence.dataSource" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="${jdbc.driverClassName}" />
<property name="url" value="${jdbc.db.url}" />
<property name="username" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="defaultAutoCommit" value="false" />
<property name="poolPreparedStatements" value="true" />
<property name="initialSize" value="20" />
<property name="maxActive" value="30" />
<property name="maxIdle" value="25" />
</bean>
<bean id="persistence.sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="persistence.dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.show_sql">${hibernate.show_sql}</prop>
<prop key="hibernate.dialect">${hibernate.dialect}</prop>
<prop key="hibernate.hbm2ddl.auto">${hibernate.hbm2ddl.auto}</prop>
<prop key="hibernate.cglib.use_reflection_optimizer">true</prop>
<prop key="hibernate.connection.autocommit">false</prop>
<prop key="hibernate.query.factory_class">org.hibernate.hql.ast.ASTQueryTranslatorFactory</prop>
</props>
</property>
<property name="mappingLocations">
<list>
<value>classpath:mappings/items/servicio.hbm.xml</value>
<value>classpath:mappings/items/stockable.hbm.xml</value>
<value>classpath:mappings/items/bigstockable.hbm.xml</value>
</list>
</property>
</bean>
<!-- Daos beans -->
<bean id="servicioDao" class="daos.ServicioDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
</bean>
<bean id="stockableDao" class="daos.StockableDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
</bean>
<bean id="bigStockableDao" class="daos.BigStockableDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
</bean>
In that xml i make my daos with it sessionFactory, but when i startup the project i got java.lang.IllegalArgumentException: 'sessionFactory' or 'hibernateTemplate' is required, because my hibernateTemplate is null.
My daos extends from HibernateDaoSupport and i know that if you give to your dao a sessionFactory it will create automatically an hibernateTemplate, and idk what could be happening.
My daos have a #Repository (example #Repository(value="servicioDao"))
And the services the #Service with the #Autowired in the setter
and i am adding them in the contex
<context:component-scan base-package="controllers" />
<context:component-scan base-package="servicios" />
<context:component-scan base-package="daos" />
I just add this in the persistence-context.xml
<!-- Daos beans -->
<bean id="servicioDao" class="daos.ServicioDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<bean id="stockableDao" class="daos.StockableDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
<bean id="bigStockableDao" class="daos.BigStockableDao" >
<property name="sessionFactory" ref="persistence.sessionFactory" />
<property name="hibernateTemplate" ref="hibernateTemplate" />
</bean>
I get the same error.
Some of my daos code:
#Repository(value="servicioDao")
#SuppressWarnings("serial")
public class ServicioDao extends GenericHome<Servicio>{
public ServicioDao(){}
#Override
protected Class<Servicio> getDomainClass() {
return Servicio.class;
}
}
public abstract class GenericHome<T> extends HibernateDaoSupport implements Serializable{
protected Class<T> persistentClass = this.getDomainClass();
protected abstract Class<T> getDomainClass();
}
public class ServicioService {
private ServicioDao servicioDao;
public ServicioService(){}
public ServicioDao getServicioDao() {
return servicioDao;
}
#Autowired
public void setServicioDao(ServicioDao servicioDao) {
this.servicioDao = servicioDao;
}
}
I noticed that when i use #Service and #Repository, beans arent created by the xml, so when it gave me the error "'sessionFactory' or 'hibernateTemplate' is required" was because the dao was created but never filled its sessionFactory, so to use my xml files i created the controller like a normal bean
Try changing your bean definitions for this:
<bean id="servicioDao" class="daos.ServicioDao" >
<constructor-arg>
<ref bean="persistence.sessionFactory" />
</constructor-arg>
</bean>
It means that you are passing the sessionFactory in the constructor of your DAO class.
You also have to write the full pass in your "class" parameter.
<bean id="servicioDao" class="full.package.path.to.ServicioDao" >
Next, in your DAO class write something like this:
#Repository
public class ServicioDao{
private SessionFactory sessionFactory;
public ServicioDao() {
}
/**
* Constructor.
*
* #since 1.0
*/
public ServicioDao(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
...
...
}
Finally, in your controllers, you can use the DAO class as follows:
...
#Autowired
ServicioDao servicioDao;
...
servicioDao.getServicioDao();
Notice that you don't need to make new ServicioDao();.
Do it for every DAO class.
I am new to Spring framework; need some clarifications on how the SessionFactory object Dependency injection is working in below code.
spring-servlet.xml
<context:annotation-config />
<context:component-scan base-package="com.employee" />
<bean id="jspViewResolver"
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass"
value="org.springframework.web.servlet.view.JstlView" />
<property name="prefix" value="/WEB-INF/jsp/" />
<property name="suffix" value=".jsp" />
</bean>
<bean id="messageSource"
class="org.springframework.context.support.ReloadableResourceBundleMessageSource">
<property name="basename" value="classpath:messages" />
<property name="defaultEncoding" value="UTF-8" />
</bean>
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"
p:location="/WEB-INF/jdbc.properties" />
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close"
p:driverClassName="${jdbc.driverClassName}"
p:url="${jdbc.databaseurl}" p:username="${jdbc.username}"
p:password="${jdbc.password}" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:employee.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<tx:annotation-driven />
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
EmployeeDAOImpl.java
import org.hibernate.SessionFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;
#Repository
public class EmployeeDAOImpl implements EmployeeDAO {
#Autowired
private SessionFactory sessionFactory;
#Override
public void addEmployee(EmployeeForm employee) {
sessionFactory.getCurrentSession().save(employee);
}
}
How is the sessionFactory getting initialized with a SessionFactory object here?
What I understand
In the sprng-servlet.xml file, the DI of sessionFactory is happening in the below code:
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
Now, if I open the source code for the class org.springframework.orm.hibernate3.HibernateTransactionManager, then I can see the below section:
private SessionFactory sessionFactory;
public HibernateTransactionManager(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
afterPropertiesSet();
}
public void setSessionFactory(SessionFactory sessionFactory){
this.sessionFactory = sessionFactory;
}
public SessionFactory getSessionFactory(){
return this.sessionFactory;
}
which means the sessionFactory class variable of org.springframework.orm.hibernate3.HibernateTransactionManager has been initializd.
Now my Query:
In my code posted above, how is the sessionFactory of class EmployeeDAOImpl.java getting initialized? I can't find any relation between the sessionFactory of class org.springframework.orm.hibernate3.HibernateTransactionManager (where DI is happening) and the sessionFactory of class EmployeeDAOImpl.java (which I wrote). Then how is it working?
Please explain - totally confused !!!
<bean id="sessionFactory"
class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation">
<value>classpath:employee.cfg.xml</value>
</property>
<property name="configurationClass">
<value>org.hibernate.cfg.AnnotationConfiguration</value>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
You have defined the session factory bean in you context file. During the application bootstrap, the spring context is loaded and this session factory bean is initialized by spring as a singleton instance.
<context:annotation-config />
<context:component-scan base-package="com.employee" />
#Autowired
private SessionFactory sessionFactory;
And since you have enabled the annotation-config and component-scan and declared #Autowired in your DAOImp, this is the reason Spring knows the place to inject the session factory bean properly.
This configuration is enabled the transaction manager annotation.
Example:
#Transactional
public void addEmployee(EmployeeForm employee){...}
Here is the suggestion.
Transactional annotation is better to be placed in service layer instead of DAO layer. You need to make sure the annotation is placed on the concrete class unless you use the interface-proxy in your component-scan.
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
This piece of configuration is set the transaction manager bean which lets transaction manager knows which session factory it needs to manage with.
Therefore the configuration of bean
id="transactionManager" sets the transaction manager with the proper hibernate session factory.
tx:annotation-driven configuration enables the annotation-based transaction manager in code level.
Hope the explanation is helpful for you. :)
This is the first time I can't find a solution to my problem on stackoverflow:
I'm trying to create an executable-jar standalone application with annotation-based autowiring, but I can't get the runnable jar file (exported from Eclipse as runnable JAR file) to do it's job. It does run as Java application from Eclipse directly, just not as standalone app via console > java -jar test.jar.
Exception in thread "main" java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
at java.lang.reflect.Method.invoke(Method.java:597)
at org.eclipse.jdt.internal.jarinjarloader.JarRsrcLoader.main(JarRsrcLoader.java:58)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'handler': Injection of autowired dependen
cies failed; nested exception is org.springframework.beans.factory.BeanCreationException: Could not autowire field: private com.example.serv
ice.UserService com.example.controller.TestHandler.userService; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionEx
ception: No qualifying bean of type [com.example.service.UserService] found for dependency: expected at least 1 bean which qualifies as auto
wire candidate for this dependency. Dependency annotations: {#org.springframework.beans.factory.annotation.Autowired(required=true)}
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBe
anPostProcessor.java:288)
I tried to avoid such problems by following the pattern 'Initialize autowiring manually' described on this blog: http://sahits.ch/blog/?p=2326 to no avail.
Note that I'm also using Hibernate JPA without a persistence.xml (therefore <tx:annotation-driven/> ) - and don't get obstructed by the two databases I use, it works fine when running from within Eclipse.
Main.java:
public class Main {
#Autowired
private TestRunner testRunner;
public Main() {
final ApplicationContext context = new ClassPathXmlApplicationContext("app-context.xml");
AutowireCapableBeanFactory acbFactory = context.getAutowireCapableBeanFactory();
acbFactory.autowireBean(this);
}
public static void main(String[] args) throws Exception {
Main main = new Main();
main.testRunner.run();
}
}
TestRunner.java:
#Component
public class TestRunner {
#Autowired
Handler handler;
public void run() {
handler.doTest();
}
}
TestHandler.java (groupId and groupName will be set in a later stage):
#Controller
public class TestHandler implements Handler {
private static Log syslog = LogFactory.getLog(TestHandler.class);
#Autowired
private UserService userService;
#Autowired
private GroupService groupService;
private Long groupId;
private String groupName;
public void doTest() {
if (groupId != null) {
List<User> users = userService.loadUsersByGroupId(groupId);
syslog.debug("Amount of users found: " + users.size());
} else {
syslog.debug("groupId is null");
}
if (groupName != null) {
List<Group> groups = groupService.loadGroupsByName(groupName);
syslog.debug("Amount of groups found: " + groups.size());
} else {
syslog.debug("groupName is null");
}
}
public void setGroupId(Long groupId) {
this.groupId = groupId;
}
public void setGroupName(String groupName) {
this.groupName = groupName;
}
}
UserServiceImpl.java:
#Service
public class UserServiceImpl implements UserService {
#Autowired
UserDAO userDAO;
#Override
public List<User> loadUsersByGroupId(long id) {
return userDAO.findAllByGroupId(id);
}
...
UserDAOImpl.java:
#Repository
#Transactional("db1")
public class UserDAOImpl implements UserDAO {
#PersistenceContext(unitName="entityManagerDb1")
private EntityManager em;
#SuppressWarnings("unchecked")
#Override
public List<User> findAllByGroupId(long id) {
Query query = em.createQuery("select distinct u from User u " +
"where u.groupId = :groupId");
query.setParameter("groupId", id);
return query.getResultList();
}
...
app-context.xml (uses annotation-configured JPA, uses two dbs):
<?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:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:jpa="http://www.springframework.org/schema/data/jpa"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
"
>
<context:annotation-config/>
<context:component-scan base-package="com.example"/>
<!-- db1 -->
<bean id="dataSourceDb1" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/db1?characterEncoding=UTF-8" />
<property name="user" value="root" />
<property name="password" value="root" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="maxStatements" value="0" />
<property name="preferredTestQuery" value="SELECT 1" />
<property name="idleConnectionTestPeriod" value="600" />
</bean>
<bean id="entityManagerFactoryDb1" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="entityManagerDb1"/>
<property name="dataSource" ref="dataSourceDb1"/>
<property name="packagesToScan">
<list>
<value>com.example.domain.db1</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.connection.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
</props>
</property>
</bean>
<!-- Configure transaction manager for JPA -->
<bean id="transactionManagerDb1" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryDb1"/>
<qualifier value="db1"/>
</bean>
<!-- db2 -->
<bean id="dataSourceDb2" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/db2?characterEncoding=UTF-8" />
<property name="user" value="root" />
<property name="password" value="root" />
<property name="minPoolSize" value="5" />
<property name="maxPoolSize" value="10" />
<property name="maxStatements" value="0" />
<property name="preferredTestQuery" value="SELECT 1" />
<property name="idleConnectionTestPeriod" value="600" />
</bean>
<bean id="entityManagerFactoryDb2" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="entityManagerDb2"/>
<property name="dataSource" ref="dataSourceDb2"/>
<property name="packagesToScan">
<list>
<value>com.example.domain.db2</value>
</list>
</property>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="false"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQL5InnoDBDialect"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<prop key="hibernate.connection.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">validate</prop>
<prop key="hibernate.use_outer_join">true</prop>
<prop key="hibernate.connection.characterEncoding">UTF-8</prop>
<prop key="hibernate.connection.useUnicode">true</prop>
</props>
</property>
</bean>
<bean id="transactionManagerDb2" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactoryDb2"/>
<qualifier value="db2"/>
</bean>
<tx:annotation-driven />
</beans>
It drives me crazy that running it inside Eclipse just works as expected. Is the Eclipse export feature somewhat limited? Any hint to another framework for creating runnable jar files?
If it is running from eclipse and not running from the exported jar file, then it is a problem with the export
In the export window there is a checkbox saying Add directory entries that should be checked for component-scan to work
When you run it inside Eclipse all the Spring dependencies and others are loaded into your classpath, but when you export you application as a jar, only your classes get exported, not the dependencies classes.
There are generally two way you can achieve a standlone jar. You can create an 'uber jar' (see Is it possible to create an "uber" jar containing the project classes and the project dependencies as jars with a custom manifest file?) where all you dependency jars got expanded into one single jar. However this method could be risky because if the jars have same file names (eg: same config file inside META-INF) they can overwrite each other
The other more appropriate method is to use maven-dependency-plugin (see dependency:copy) to copy all your dependency into a folder "dependencies". And then run your jar with
java -cp "myjar.jar;dependencies/*" org.mycompany.MainClass
This isn't really a standalone jar, but more a standalone folder. The downside is everytime you add/remove the dependencies (eg: from maven) you have to do the same to your dependencies folder
I'm trying to create a persistance project so it can be re-used by some other projects I'm building on top. I.e it will be used by a web service/spring mvc project and by standalone jar which does some file processing.
I've used hibernate with spring mvc before but never as a standalone executable java jar so I have everything setup and working(application context) :
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns: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">
<!-- Enable annotation style of managing transactions -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Root Context: defines shared resources visible to all other web components -->
<!-- HIBERNATE -->
<bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location" value="classpath:spring.properties" />
</bean>
<bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driverClassName}" />
<property name="jdbcUrl" value="${jdbc.databaseurl}" />
<property name="user" value="${jdbc.username}" />
<property name="password" value="${jdbc.password}" />
<property name="acquireIncrement" value="5" />
<property name="idleConnectionTestPeriod" value="60"/>
<property name="maxPoolSize" value="100"/>
<property name="maxStatements" value="50"/>
<property name="minPoolSize" value="10"/>
</bean>
<bean id="sessionFactory" class="org.springframework.orm.hibernate3.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="mappingResources">
<list> <value>com/project/utility/persistence/mapping/TestProp.hbm.xml</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">${jdbc.dialect}</prop>
<prop key="hibernate.show_sql">true</prop>
</props>
</property>
</bean>
<bean id="transactionManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<!-- END HIBERNATE -->
</beans>
When I test it from main class everything looks ok with mapping/dependencies :
public static void main(String[] args) {
ClassPathXmlApplicationContext ctx = new ClassPathXmlApplicationContext("appCtx.xml");
}
What I want to do next is to build few dao classes which will get some data and I'd build some interface above that so it can be re-used by both webservice and processing tool as a jar(maven dependency).
In order to build dao classes I need sessionFactory to be != null always. How do I do this?
There are many approaches to this. One solution I use is to use the javax.persistence.PersistenceContext annotation. Spring will respect this annotation and inject a proxy to a thread local EntityManager. Provided your DAO is created by Spring this allows access to the entity manager from within your DAO.
public class DAO {
private EntityManager entityManager;
#PersistenceContext
public void setEntityManager(EntityManager entityManager) {
this.entityManager = entityManager;
}
}
#Repository
public class MyDAO {
#Autowired
private SessionFactory sessionFactory;
// ...
}
and add the MyDAO bean to the context XML file, or simply add the following lines to this file:
<context:annotation-config />
<context:component-scan base-package="one.of.the.parent.packages.of.your.dao" />