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
Related
Im trying to save the data into PostgreSQL database, I configure my dataSource bean:
<bean id="dataSource"
class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="org.postgresql.Driver"/>
<property name="url" value="jdbc:postgresql://localhost/testdb"/>
<property name="username" value="root"/>
<property name="password" value="123"/>
<!-- <property name="initialSize" value="5"/>-->
<!-- <property name="maxActive" value="10"/>-->
</bean>
then insert them into sessionFactory
<bean id="sessionFactory"
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="packagesToScan">
<list>
<value>com.nazik.domain</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="dialect">org.hibernate.dialect.PostgreSQL10Dialect</prop>
</props>
</property>
</bean>
and configure transactionManager
<bean id="transactionManager"
class="org.springframework.orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
but when I start transaction using code:
#Override
public void createPerson(final Person person) {
transactionTemplate.execute(new TransactionCallback<Void>() {
public Void doInTransaction(TransactionStatus transactionStatus){
try{
createPerson(person);
}catch (RuntimeException e){
transactionStatus.setRollbackOnly();
throw e;
}
return null;
}
});
}
i have got an error:
Exception in thread "main" org.springframework.beans.factory.BeanNotOfRequiredTypeException: Bean named 'transactionManager' is expected to be of type 'org.hibernate.SessionFactory' but was actually of type 'org.springframework.orm.hibernate5.HibernateTransactionManager'
at org.springframework.beans.factory.support.AbstractBeanFactory.adaptBeanInstance(AbstractBeanFactory.java:417)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:398)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:213)
at org.springframework.context.support.AbstractApplicationContext.getBean(AbstractApplicationContext.java:1160)
please explain me what am I doing wrong
I'm not completely sure since I have no way to test but at least the exception says that the configuration of 'transaction manager' receives the wrong type of parameter.
you can test this way.
<bean id = "transactionManager"
class = "org.hibernate.SessionFactory">
<property name = "sessionFactory" ref = "sessionFactory" />
</bean>
You can try to see if it is that, I leave you as an answer since I can not comment yet.
Pdt: as a personal recommendation I suggest you use JPA since it has a simpler handling of transactions
I could test this on similar setup and configuration except I am using HibernateTemplate. Since you are using Hibernate - you should be generally using HibernateTemplate or even better JPA APIs ( which can be used as Hibernate underlying JPA implementation)
You can also use #Transactional annotation rather than programatically defining your boundaries and exception handling.
My sample configuration looks like this
<?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:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd
">
<tx:annotation-driven />
<context:component-scan base-package="springmvc"></context:component-scan>
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver"
name="viewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<bean
class="org.springframework.jdbc.datasource.DriverManagerDataSource"
name="ds">
<property name="driverClassName"
value="com.mysql.jdbc.Driver" />
<property name="url"
value="jdbc:mysql://localhost:3306/springjdbc" />
<property name="username" value="root" />
<property name="password" value="root" />
</bean>
<bean
class="org.springframework.orm.hibernate5.LocalSessionFactoryBean"
name="sessionFactory">
<property name="dataSource" ref="ds" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL57Dialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>springmvc.model.User</value>
</list>
</property>
</bean>
<bean class="org.springframework.orm.hibernate5.HibernateTemplate"
name="hibernateTemplate">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
<bean
class="org.springframework.orm.hibernate5.HibernateTransactionManager"
name="transactionManager">
<property name="sessionFactory" ref="sessionFactory"></property>
</bean>
</beans>
And my data saving code looks like this
#Autowired
private HibernateTemplate hibernateTemplate;
#Transactional
public int saveUser(User user) {
int id = (Integer)this.hibernateTemplate.save(user);
return id;
}
And I can save data in database ( MySQL in my case but that is irrelevant here)
I continue getting the following error:
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException:
No qualifying bean of type 'StorageItemRepository'
My beans.xml is set to find all - located in META-INF/beans.xml of every module resource file. My Repository class does have #Repository on it and my web.xml is definitely configured to find the bean.
It's worth noting - this working when deployed - just not for the below unit test.
My unit test:
/**
* Test for {#link StorageItemRepository}
*/
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration({"classpath:JDBCConfig.xml"})
#EnableTransactionManagement
#EnableJpaRepositories(basePackages = {"com.app.storage.persistence.repository"})
public class StorageItemRepositoryTest {
/** {#link StorageItemRepository} */
#Autowired
private StorageItemRepository storageItemRepository;
/**
* Finds all storage items in db.
*/
#Test
public void checkFindAllItems(){
final StorageItemPersistenceModel storageItemPersistenceModel = new StorageItemPersistenceModel();
storageItemPersistenceModel.setId(1L);
storageItemPersistenceModel.setDateStored(new DateTime());
storageItemPersistenceModel.setName("Name");
storageItemRepository.save(storageItemPersistenceModel);
}
}
JDBCConfig file:
<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-3.0.xsd">
<bean name="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/storage_app_schema" />
<property name="username" value="root" />
<property name="password" value="dollar123" />
</bean>
<bean id="myEmf" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="packagesToScan" value="com.app.storage.persistence.model" />
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter"/>
<property name="persistenceUnitName" value="app_test"/>
<property name="jpaProperties">
<props>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true"/>
<property name="generateDdl" value="true"/>
<property name="databasePlatform" value="org.hibernate.dialect.MySQLDialect"/>
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="myEmf"/>
</bean>
</beans>
The persistence.xml is definitely fine and working so not the cause.
How are you running the unit test?
Since it is working when deployed, and not in the unit test, I am inclined to suspect that the unit test execution has a missing classpath, such as JDBCConfig.xml doesn't exist in the execution classpath
Whenever I on click submit button with some value, I want to select some columns from database and show it on my jsp page. The form is successfully submitted but I'm getting this error:
java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to com.psc.Entity.CandidateappearagainstadvtcodeEntity
So I think whatever data the repository is returning is not mapped with Entity. Please suggest, how to resolve this issue?
Controller:
#RequestMapping(value = "/getCandidateDetails", method = RequestMethod.POST)
public String getCandidateDetails(Model model,#RequestParam("studentmasterid") String studentmasterid){
System.out.println(studentmasterid);
List<CandidateappearagainstadvtcodeEntity> candidates=candidateappearagainstadvtcodeEntityRepository.findBystudentmasterid(studentmasterid);
return "payments";
}
Model looks like this:
#Entity
#Table(name = "CANDIDATEAPPEARAGAINSTADVTCODE", schema = "PSCNEPALCOMMERCIALDATABASEU1", catalog = "")
public class CandidateappearagainstadvtcodeEntity {
private long id;
private String advertisementcode;
private Integer ageonlastdateday;
private Integer ageonlastdatemonth;
private Integer ageonlastdateyear;
private String applicationnumber;
private String attendancestatus;
private String candidatefirstname;
private String dateofbirthinnepali;
private String documentverificationstatus;
private String examinationcenterid;
private String examresultsstatus;
private String fathername;
private Long firstcoding;
private String studentmasterid;
//getters setters//
Repository:
public interface CandidateappearagainstadvtcodeEntityRepository extends JpaRepository<CandidateappearagainstadvtcodeEntity,Long> {
#Query("select c.studentmasterid,c.advertisementcode,c.candidatefirstname from CandidateappearagainstadvtcodeEntity c where c.studentmasterid=?1")
List<CandidateappearagainstadvtcodeEntity> findBystudentmasterid(String masterId);
}
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:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
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-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-3.2.xsd
http://www.springframework.org/schema/data/jpa http://www.springframework.org/schema/data/jpa/spring-jpa-1.0.xsd">
<context:annotation-config/>
<context:component-scan base-package="com.psc"/>
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>/WEB-INF/db.properties</value>
</property>
</bean>
<!-- BoneCP configuration -->
<bean id="mainDataSource" class="com.jolbox.bonecp.BoneCPDataSource" destroy-method="close">
<property name="driverClass" value="${jdbc.driver}" />
<property name="jdbcUrl" value="${jdbc.url}" />
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="idleConnectionTestPeriodInMinutes" value="60"/>
<property name="idleMaxAgeInMinutes" value="240"/>
<property name="maxConnectionsPerPartition" value="30"/>
<property name="minConnectionsPerPartition" value="10"/>
<property name="partitionCount" value="3"/>
<property name="acquireIncrement" value="5"/>
<property name="statementsCacheSize" value="100"/>
<property name="releaseHelperThreads" value="3"/>
</bean>
<!-- SPRING - JPA -->
<jpa:repositories
base-package="com.psc" />
<bean class="org.springframework.orm.jpa.JpaTransactionManager"
id="transactionManager">
<property name="entityManagerFactory"
ref="entityManagerFactory" />
<property name="jpaDialect">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaDialect" />
</property>
</bean>
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="mainDataSource" />
<property name="packagesToScan" value="com.psc"/>
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="generateDdl" value="true" />
<property name="showSql" value="false"/>
<property name="databasePlatform" value="org.hibernate.dialect.Oracle12cDialect"/>
<property name="database" value="ORACLE"/>
</bean>
</property>
<property name="jpaProperties">
<props>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.dialect">org.hibernate.dialect.Oracle12cDialect</prop>
</props>
</property>
</bean>
</beans>
A JPA repository usually returns the domain model. From the docs
Spring Data Repositories usually return the domain model when using query methods. However, sometimes, you may need to alter the view of that model for various reasons. In this section, you will learn how to define projections to serve up simplified and reduced views of resources.
Your repository method findBystudentmasterid will be returning a list Object[] hence the ClassCastException.If you want to get specific columns try Projections.
Chekout the docs and this answer on how to use projections.
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.
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" />