Problems with testing JdbcDao by DBUnit - spring

I have AuthorJDBCDAO class with basic CRUD methods which extends AbstractJDBCDAO class and implements AuthorDAO interface.
I tested all methods via psv main() method and everything was fine.
But Now I have to test it's methods using DBUnit. And here my troubles start.
I try to test just only create() method and it isn't working properly.
I'm using Unitils, Spring DI, Oracle DB to create my application.
I inject bean DataSource(dbcp2) to beanAuthorJDBCDAO. I use XML configuration for injection beans.
Here's my source code and configuration files.
Test class.
#SpringApplicationContext({"spring-test-config.xml"})
#DataSet(value = "AuthorDAOTest.xml", loadStrategy = CleanInsertLoadStrategy.class)
public class AuthorDAOTest extends UnitilsJUnit4 {
#SpringBean("authorJDBCDAO")
private AuthorJDBCDAO authorDAO;
#Test
public void testCreate() throws DAOException {
Author expected = new Author();
expected.setName("BLABLABLA");
expected.setExpiredDate(Timestamp.valueOf(LocalDateTime.now()));
Author result = null;
result = authorDAO.create(expected);
assertEquals(expected.getId(), result.getId());
System.out.println("Hello from test");
}
Here's stacktrace from execution of Test class.
newsportal.exception.DAOException: java.sql.SQLException: Connection is null.
at newsportal.dao.impl.AbstractJDBCDAO.create(AbstractJDBCDAO.java:115)
at com.epam.ivanou.newsportal.dao.impl.AuthorJDBCDAOTest.testCreate(AuthorJDBCDAOTest.java:33)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at org.junit.internal.runners.TestMethod.invoke(TestMethod.java:68)
at org.junit.internal.runners.MethodRoadie.runTestMethod(MethodRoadie.java:108)
at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runTestMethod(UnitilsJUnit4TestClassRunner.java:204)
at org.junit.internal.runners.MethodRoadie$2.run(MethodRoadie.java:89)
at org.junit.internal.runners.MethodRoadie.runBeforesThenTestThenAfters(MethodRoadie.java:97)
at org.unitils.UnitilsJUnit4TestClassRunner$TestListenerInvokingMethodRoadie.runBeforesThenTestThenAfters(UnitilsJUnit4TestClassRunner.java:186)
at org.junit.internal.runners.MethodRoadie.runTest(MethodRoadie.java:87)
at org.junit.internal.runners.MethodRoadie.run(MethodRoadie.java:50)
at org.unitils.UnitilsJUnit4TestClassRunner.invokeTestMethod(UnitilsJUnit4TestClassRunner.java:95)
at org.junit.internal.runners.JUnit4ClassRunner.runMethods(JUnit4ClassRunner.java:59)
at org.unitils.UnitilsJUnit4TestClassRunner.access$000(UnitilsJUnit4TestClassRunner.java:42)
at org.unitils.UnitilsJUnit4TestClassRunner$1.run(UnitilsJUnit4TestClassRunner.java:60)
at org.junit.internal.runners.ClassRoadie.runUnprotected(ClassRoadie.java:34)
at org.junit.internal.runners.ClassRoadie.runProtected(ClassRoadie.java:44)
at org.unitils.UnitilsJUnit4TestClassRunner.run(UnitilsJUnit4TestClassRunner.java:67)
at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:78)
at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:212)
at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:68)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:140)
Caused by: java.sql.SQLException: Connection is null.
at org.apache.commons.dbcp2.DelegatingConnection.checkOpen(DelegatingConnection.java:608)
at org.apache.commons.dbcp2.DelegatingConnection.prepareStatement(DelegatingConnection.java:286)
at com.epam.ivanou.newsportal.dao.impl.AbstractJDBCDAO.create(AbstractJDBCDAO.java:106)
... 29 more
Fragment of code of AbstractJDBCDAO class. In which I get this exception. I tried to debug it and found, that in the second try-catch-with-resources block connection is null. But I can't understand, how does it occur if I try to get connection from DataSource which is BasicDataSource and support connection pooling.
#Override
public T create(T object) throws DAOException {
T persistInstance;
// Add the record
String sql = getCreateQuery();
String idName = getIdString();
String tableName = getTableName();
try (Connection connection = DataSourceUtils.getConnection(dataSource);
PreparedStatement statement = connection.prepareStatement(sql)) {
System.out.println("connection: "+ connection + " data source: " + dataSource);
prepareStatementForInsert(statement, object);
int count = statement.executeUpdate();
if (count != 1) {
throw new DAOException("On persist modify more then 1 record: " + count);
}
} catch (Exception e) {
throw new DAOException(e);
}
// Get recently inserted record
sql = getSelectQuery() + " WHERE " + idName + " = (SELECT MAX(" + idName + ") FROM "
+ tableName + ")";
try (Connection connection = DataSourceUtils.getConnection(dataSource);
PreparedStatement statement = connection.prepareStatement(sql)) //here is connection is null and SQLException is thrown {
System.out.println("connection: "+ connection + " data source: " + dataSource); //TODO connection is null in test method, but is good when using main() method
ResultSet rs = statement.executeQuery();
List<T> list = parseResultSet(rs);
if ((list == null) || (list.size() != 1)) {
throw new DAOException("Exception on findByPK new persist data.");
}
persistInstance = list.iterator().next();
} catch (Exception e) {
throw new DAOException(e);
}
return persistInstance;
}
here're configuration files for my beans:
dao-beans.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
<bean id="authorJDBCDAO" class="newsportal.dao.impl.AuthorJDBCDAO">
<constructor-arg ref="dataSource"/>
</bean>
database-test-config.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-4.2.xsd">
<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="location">
<value>db_test.properties</value>
</property>
</bean>
<bean id="dataSource" class="org.apache.commons.dbcp2.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="${jdbc.driverClassName}"/>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
<property name="maxIdle" value="${jdbc.maxIdle}"/>
<property name="minIdle" value="${jdbc.minIdle}"/>
<property name="maxWaitMillis" value="${jdbc.maxWaitMillis}"/>
<property name="initialSize" value="${jdbc.initialSize}"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
</beans>
spring-test-config.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<import resource="database-test-config.xml" />
<import resource="dao-beans.xml" />
</beans>
db_test.properties
jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:#localhost:1521:xe
jdbc.username=Yahor_test
jdbc.password=1234
jdbc.maxIdle=100
jdbc.minIdle=10
jdbc.maxWaitMillis=10000
jdbc.initialSize=10
And here's Simple java class for testing:
public class Test {
public static void main(String[] args) throws DAOException {
ApplicationContext ctx = new ClassPathXmlApplicationContext("spring-config.xml");
AuthorJDBCDAO authorDAO = (AuthorJDBCDAO) ctx.getBean("authorJDBCDAO");
Author author = new Author();
author.setName("Yahor");
author = authorDAO.create(author);
System.out.println(author.getId());
}
And it's working fine =)
May be smth wrong with transactional configurations in my DBUnit Test class?

Problem is solved. I should close connection via DataSourceUtils.doReleaseConnection(). Otherwise connection will be closed physically. It was the keystone of my trouble.

Related

session/entitymanager is closed

I have this Hibernate dao and it works fine while testing on my local machine. But for some transactions it throws IllegalStateException. I believe this is because multiple users are hitting it at the same time. (I may be wrong).
UpdatePaymentDao
#Repository
public class UpdatePaymentImpl implements UpdatePayment {
#Autowired
SessionFactory sessionFactory;
Session session;
Transaction trans;
private static final long LIMIT = 100000000000L;
private static final long LIMIT2 = 10000000000L;
private static long last = 0;
public static long getUniqueID() {
// 10 digits.
long id = (System.currentTimeMillis() % LIMIT) + LIMIT2;
System.out.println("id"+id);
System.out.println("system time"+System.currentTimeMillis());
System.out.println("milssiiiiii=============="
+ System.currentTimeMillis());
if (id <= last) {
id = (last + 1) % LIMIT;
}
return last = id;
}
public PaymentResponse updatePayment(#RequestBody FcgoUpdateParam updateParam) {
FcgoUpdateParam fcgoUpdateParam= new FcgoUpdateParam();
Double amountPaid=Double.parseDouble(updateParam.getAmountPaid());
String depositSlioNo=updateParam.getVoucherno();
String masterId= updateParam.getMasterId();
String advCode=updateParam.getAdvCode();
PaymentResponse paymentResponse = new PaymentResponse();
long uuid = getUniqueID();
try{
System.out.println("generated uuid "+uuid);
DateFormat dateFormat =new SimpleDateFormat("dd-MMM-yy h.mm.ss.000000000 a");
SimpleDateFormat dms = new SimpleDateFormat("dd-MM-yyyy");
String cdate = updateParam.getChallanDate();
Date ddate= dms.parse(cdate);
String challandate = dateFormat.format(ddate);
String office = updateParam.getOffice();
String username = updateParam.getUsername();
Long id = getIdOnChallanTable()+1L;
String challanid = String.valueOf(uuid);
ChallanEntity challanEntity = new ChallanEntity();
challanEntity.setAdvtcode(updateParam.getAdvCode());
challanEntity.setAmount(amountPaid);
challanEntity.setName(updateParam.getName());
challanEntity.setOffice(office);
challanEntity.setUsername(username);
challanEntity.setStatus(updateParam.getStatus());
challanEntity.setChallandate(challandate);
challanEntity.setChallanid(uuid);
challanEntity.setChallantime("null");
challanEntity.setVoucherno(updateParam.getVoucherno());
System.out.println(challanEntity.getId());
System.out.println("challan saved");
session=sessionFactory.openSession();
trans=session.beginTransaction();
Query query= session.createQuery("update CandidateappearagainstadvtcodeEntity cd set
cd.paymentstatus='Completed',cd.amountpaid=:depoFee,cd.challanid=:challanid where
cd.studentmasterid=:masterid and cd.advertisementcode=:advCode");
System.out.println(updateParam.getAdvCode());
query.setParameter("depoFee",updateParam.getAmountPaid());
query.setParameter("challanid",challanid);
query.setParameter("masterid",masterId);
query.setParameter("advCode",advCode);
Query query1 =session.createQuery(" update CandidateappeartoadvtnumberEntity cnd
set cnd.paymentstatus='Completed', cnd.depositedfee=:depofee where
cnd.studentmasterid=:masterid
and cnd.advertisementcode=:advcode");
String masterId1= updateParam.getMasterId();
String advCode1=updateParam.getAdvCode();
System.out.println("updateCandidateappearagainstadvtcodeEntity ");
query1.setParameter("depofee",amountPaid);
query1.setParameter("masterid",masterId1);
query1.setParameter("advcode",advCode1);
//added code
final long start = System.nanoTime();
System.out.println("before executing excute update queries");
System.out.println("checking update query timings");
query.executeUpdate();
query1.executeUpdate();
//added code
final long end = System.nanoTime();
System.out.println("after executing two update queries, it took: " +
((end - start) / 1000000) + "ms");
//printing all values for test
//printing for candidateappearagainstcode table
System.out.println("printing candidate appear against code table");
System.out.println("the received challan id is: " +challanid);
System.out.println("the received deposited fee is :"+amountPaid);
System.out.println("the received advt code is : "+advCode);
System.out.println("the received master id is : "+masterId);
System.out.println("values committed on psc database");
try {
final String uri = "http://xx.x.x.xx:xxxx/FcgoApi/api/savePayment";
RestTemplate restTemplate = new RestTemplate();
paymentResponse = restTemplate.postForObject(uri, updateParam,
PaymentResponse.class);
if (paymentResponse.getVoucherNo() != null) {
challanEntity.setVoucherno(paymentResponse.getVoucherNo());
session.save(challanEntity);
session.update(challanEntity);
trans.commit();
return paymentResponse;
}else {
trans.rollback();
}
}catch (Exception ex){
ex.printStackTrace();
trans.rollback();
}
}catch (Exception e){
System.out.println("update error " +e);
trans.rollback();
}finally {
session.close();
}
return paymentResponse;
}
// [...]
}
applicationContext.xml
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean class="org.springframework.beans.factory.config.
PropertyPlaceholderConfigurer">
<property name="location">
<value>/WEB-INF/db.properties</value>
</property>
</bean>
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource"></property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">
org.hibernate.dialect.Oracle10gDialect</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.format_sql">true</prop>
<prop key="hibernate.connection.url">
jdbc:oracle:thin:#x.x.x.x:1521:xxx</prop>
<prop key="hibernate.connection.driver_class">
oracle.jdbc.driver.OracleDriver</prop>
<prop key="hibernate.c3p0.timeout">18000</prop>
</props>
</property>
<property name="packagesToScan">
<list>
<value>com.psc</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.
orm.hibernate5.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.
datasource.DriverManagerDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"></property>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
</beans>
error log:
java.lang.IllegalStateException: Session/EntityManager is closed
at org.hibernate.internal.AbstractSharedSessionContract.
checkOpen(AbstractSharedSessionContract.java:328)
at org.hibernate.engine.spi.SharedSessionContractImplementor
checkOpen(SharedSessionContractImplementor.java:126)
at org.hibernate.internal.SessionImpl.fireSave(SessionImpl.java:669)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:665)
at org.hibernate.internal.SessionImpl.save(SessionImpl.java:660)
at com.psc.dao.UpdatePaymentImpl.updatePayment(UpdatePaymentImpl.java:127)
at com.psc.services.UpdatePaymentServiceImpl.updatePayment
(UpdatePaymentServiceImpl.java:26)
at sun.reflect.GeneratedMethodAccessor92.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at org.springframework.aop.support.AopUtils
.invokeJoinpointUsingReflection(AopUtils.java:333)
at org.springframework.aop.framework.ReflectiveMethodInvocation.
invokeJoinpoint(ReflectiveMethodInvocation.java:190)
at org.springframework.aop.framework.ReflectiveMethodInvocation.
proceed(ReflectiveMethodInvocation.java:157)
at org.springframework.transaction.interceptor.TransactionInterceptor$1
.proceedWithInvocation(TransactionInterceptor.java:99)
at org.springframework.transaction.interceptor.TransactionAspectSupport.
invokeWithinTransaction(TransactionAspectSupport.java:282)
at org.springframework.transaction.interceptor.TransactionInterceptor.
invoke(TransactionInterceptor.java:96)
at org.springframework.aop.framework.
ReflectiveMethodInvocation.proceed(ReflectiveMethodInvocation.java:179)
at org.springframework.aop.framework.JdkDynamicAopProxy.invoke(JdkDynamicAopProxy.java:213)
at com.sun.proxy.$Proxy32.updatePayment(Unknown Source)
at com.psc.controls.UpdatePayment.updatePayment(UpdatePayment.java:26)
at sun.reflect.GeneratedMethodAccessor91.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:55)
at java.lang.reflect.Method.invoke(Method.java:508)
at org.springframework.web.method.support.
InvocableHandlerMethod.doInvoke(InvocableHandlerMethod.java:205)
at org.springframework.web.method.support.
InvocableHandlerMethod.invokeForRequest(InvocableHandlerMethod.java:133)
at org.springframework.web.servlet.mvc.method.annotation.
ServletInvocableHandlerMethod.invokeAndHandle(ServletInvocableHandlerMethod.java:97)
at org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerAdapter.invokeHandlerMethod(RequestMappingHandlerAdapter.java:827)
at org.springframework.web.servlet.mvc.method.annotation.
RequestMappingHandlerAdapter.handleInternal(RequestMappingHandlerAdapter.java:738)
at org.springframework.web.servlet.mvc.method.
AbstractHandlerMethodAdapter.handle(AbstractHandlerMethodAdapter.java:85)
at org.springframework.web.servlet.DispatcherServlet.
doDispatch(DispatcherServlet.java:963)
at org.springframework.web.servlet.DispatcherServlet
.doService(DispatcherServlet.java:897)
at org.springframework.web.servlet.FrameworkServlet
.processRequest(FrameworkServlet.java:970)
at org.springframework.web.servlet.FrameworkServlet
.doPost(FrameworkServlet.java:872)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:661)
at org.springframework.web.servlet.FrameworkServlet
.service(FrameworkServlet.java:846)
at javax.servlet.http.HttpServlet.service(HttpServlet.java:742)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter
(ApplicationFilterChain.java:231)
at org.apache.catalina.core.ApplicationFilterChain.doFilter
(ApplicationFilterChain.java:166)
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52)
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter
(ApplicationFilterChain.java:193)
update error java.lang.IllegalStateException: org.hibernate.resource.jdbc.internal.LogicalConnectionManagedImpl#4bbb6b39 is closed
You mustn't use the Session and Transaction as a class member of your dao like that. Session/EntityManager are suppose to be scoped by unit of work, they are not thread safe.
In your current state, as Spring DI create beans as singleton, if two threads use the dao at the same time the second will overwrite both Session and Transaction members which is why i suppose you get the IllegalStateExcepion.
You have to make them thread scoped by either using them as variables in methods or, if you don't need hibernate's specific method, you could go for a full JPA configuration in Spring and use #PersistenceContext/#PersistenceUnit to let the framework deal with that issue.
The Spring will create a singleton copy of the DA class.
In a multi threading scenario when a thread t1 is working on a session/transaction and thread t2 which share same sesion/transacrtion may close it. So make sure declaring these variable inside your local variable. The Scope of declaration of variable matters here.

Specify a custom web.xml to an embedded tomcat

Is there a way to specify a different web.xml from the standard WEB-INF/web.xml when using an embedded tomcat instance?
I would like to put a web.xml in my src/test/resources (or some other area) and refer to that web.xml when starting the embedded tomcat.
Here is my existing code to start the tomcat instance
tomcat = new Tomcat();
String baseDir = ".";
tomcat.setPort(8080);
tomcat.setBaseDir(baseDir);
tomcat.getHost().setAppBase(baseDir);
tomcat.getHost().setAutoDeploy(true);
tomcat.enableNaming();
Context ctx = tomcat.addWebApp(tomcat.getHost(), "/sandbox-web", "src\\main\\webapp");
File configFile = new File("src\\main\\webapp\\META-INF\\context.xml");
ctx.setConfigFile(configFile.toURI().toURL());
tomcat.start();
I am starting this server from a tomcat instance and I would like to do the following when running unit tests
turn off the contextConfigLocation
specify a custom ContextLoaderListener that sets the parent ApplicationContext of the embedded tomcat.
This file might be specified like so:
File webXmlFile = new File("src\\test\\resources\\embedded-web.xml");
Edit
After much frustration I realized that no matter what I do, I cannot persuade tomcat from looking in WEB-INF for web.xml. It appears that I must ignore the web.xml altogether and set the items in the web.xml programmatically.
I ended up with this configuration:
cucumber.xml for configuring tests
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<bean id="applicationContextProvider" class="ca.statcan.icos.sandbox.ApplicationContextProvider"/>
<bean id="sandBoxDataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="org.hsqldb.jdbcDriver" />
<property name="url" value="jdbc:hsqldb:mem:testdb;shutdown=true;" />
<property name="username" value="SA" />
<property name="password" value="" />
</bean>
<!-- Support for JPA related annotation support (#PersistenceUnit and #PersistenceContext) -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />
<!-- JTA Configuration -->
<bean id="jtaTransactionManager" class="com.atomikos.icatch.jta.UserTransactionManager"
init-method="init" destroy-method="close">
<property name="forceShutdown"><value>true</value></property>
</bean>
<bean id="jtaUserTransaction" class="com.atomikos.icatch.jta.UserTransactionImp" />
<bean id="springTransactionManager"
class="org.springframework.transaction.jta.JtaTransactionManager">
<property name="transactionManager" ref="jtaTransactionManager" />
<property name="userTransaction" ref="jtaUserTransaction" />
</bean>
<!-- JPA Entity Manager configuration -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
lazy-init="true">
<property name="persistenceUnitName" value="sandBox" />
<property name="dataSource" ref="sandBoxDataSource" />
<property name="jpaVendorAdapter">
<bean class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="database" value="SQL_SERVER" />
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
</bean>
</property>
<property name="jpaPropertyMap">
<props>
<prop key="hibernate.archive.autodetection">class</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
<!-- Second Level Cache : EHCache in dev
<prop key="hibernate.cache.provider_class">net.sf.ehcache.hibernate.EhCacheProvider</prop> -->
<prop key="hibernate.hbm2ddl.auto">create</prop>
</props>
</property>
</bean>
<bean class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<import resource="classpath:META-INF/applicationContext-core.xml" />
<import resource="classpath:META-INF/applicationContext-web.xml" />
</beans>
applicationContext-core.xml - where the services are configured
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx" xmlns:context="http://www.springframework.org/schema/context"
xmlns:jee="http://www.springframework.org/schema/jee"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.2.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-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/jee http://www.springframework.org/schema/jee/spring-jee-3.2.xsd"
default-autowire="byName">
<bean id="propertyPlaceholderConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations" value="classpath*:META-INF/fms-local.properties" />
<property name="systemPropertiesModeName">
<value>SYSTEM_PROPERTIES_MODE_OVERRIDE</value>
</property>
</bean>
<!--
Classpath scanning to load all the service classes
-->
<context:component-scan base-package="ca.statcan"
use-default-filters="false">
<context:include-filter type="regex" expression="ca\.statcan\.icos.*\.service\..*Service" />
<context:include-filter type="regex" expression="ca\.statcan\.icos.*\.builders\..*Builder" />
</context:component-scan>
<!--
Spring TransactionManager
-->
<tx:advice id="txAdvice" transaction-manager="springTransactionManager">
<tx:attributes>
<!-- all methods starting with 'get' are read-only -->
<tx:method name="get*" read-only="true" propagation="SUPPORTS" isolation="DEFAULT"/>
<tx:method name="find*" read-only="true" propagation="SUPPORTS" isolation="DEFAULT"/>
<!-- other methods use the default transaction settings -->
<tx:method name="*" read-only="false" propagation="REQUIRED" isolation="DEFAULT"/>
</tx:attributes>
</tx:advice>
<!--
AOP Weaving for all Service methods
-->
<aop:config proxy-target-class="true">
<aop:pointcut id="icosServiceMethods" expression="execution(* ca.statcan.icos..*.service.*.*(..))" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="icosServiceMethods" />
</aop:config>
</beans>
Custom ContextLoaderListener
public class EmbeddedContextLoaderListener extends ContextLoaderListener {
#Override
protected WebApplicationContext createWebApplicationContext(ServletContext sc) {
GenericWebApplicationContext context = new GenericWebApplicationContext(sc);
context.setParent(ApplicationContextProvider.getApplicationContext());
return context;
}
#Override
protected ApplicationContext loadParentContext(ServletContext servletContext) {
return ApplicationContextProvider.getApplicationContext();
}
}
Modified Embedded Tomcat Wrapper
public class EmbeddedTomcat {
/** Log4j logger for this class. */
#SuppressWarnings("unused")
private static final Logger LOG = LoggerFactory.getLogger(EmbeddedTomcat.class);
private Tomcat tomcat;
public void start() {
try {
tomcat = new Tomcat();
String baseDir = ".";
tomcat.setPort(8080);
tomcat.setBaseDir(baseDir);
tomcat.getHost().setAppBase(baseDir);
tomcat.getHost().setDeployOnStartup(true);
tomcat.getHost().setAutoDeploy(true);
tomcat.enableNaming();
Context context = tomcat.addContext("/sandbox-web", "src\\main\\webapp");
Tomcat.initWebappDefaults(context);
configureSimulatedWebXml(context);
LOG.info("Starting tomcat in: " + new File(tomcat.getHost().getAppBase()).getAbsolutePath());
tomcat.start();
} catch (LifecycleException e) {
throw new RuntimeException(e);
}
}
public void stop() {
try {
tomcat.stop();
tomcat.destroy();
FileUtils.deleteDirectory(new File("work"));
FileUtils.deleteDirectory(new File("tomcat.8080"));
} catch (LifecycleException e) {
throw new RuntimeException(e);
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public void deploy(String appName) {
tomcat.addWebapp(tomcat.getHost(), "/" + appName, "src\\main\\webapp");
}
public String getApplicationUrl(String appName) {
return String.format("http://%s:%d/%s", tomcat.getHost().getName(),
tomcat.getConnector().getLocalPort(), appName);
}
public boolean isRunning() {
return tomcat != null;
}
private void configureSimulatedWebXml(final Context context) {
// Programmatically configure the web.xml here
context.setDisplayName("Sandbox Web Application");
context.addParameter("org.apache.tiles.impl.BasicTilesContainer.DEFINITIONS_CONFIG", "/WEB-INF/tiles-defs.xml,/WEB-INF/tiles-sandbox.xml");
final FilterDef struts2Filter = new FilterDef();
struts2Filter.setFilterName("struts2");
struts2Filter.setFilterClass("org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter");
struts2Filter.addInitParameter("actionPackages", "ca.statcan.icos.sandbox.web");
context.addFilterDef(struts2Filter);
final FilterMap struts2FilterMapping = new FilterMap();
struts2FilterMapping.setFilterName("struts2");
struts2FilterMapping.addURLPattern("/*");
context.addFilterMap(struts2FilterMapping);
context.addApplicationListener("org.apache.tiles.web.startup.TilesListener");
context.addApplicationListener("ca.statcan.icos.sandbox.EmbeddedContextLoaderListener");
context.addWelcomeFile("index.jsp");
}
}
Step definitions
public class StepDefs {
#Autowired
protected EmployeeEntityService employeeEntityService;
#Given("^the following divisions exist$")
public void the_following_divisions_exist(DataTable arg1) throws Throwable {
final Employee employee = new Employee(3, "Third", "John", null, "613-222-2223");
employeeEntityService.persistEmployee(employee);
}
#Given("^there are no existing surveys$")
public void there_are_no_existing_surveys() throws Throwable {
}
#When("^I register a new survey with the following information$")
public void I_register_a_new_survey_with_the_following_information(DataTable arg1) throws Throwable {
Capabilities capabilities = DesiredCapabilities.htmlUnit();
final HtmlUnitDriver driver = new HtmlUnitDriver(capabilities);
driver.get("http://localhost:8080/sandbox-web/myFirst");
}
#Then("^the surveys are created$")
public void the_surveys_are_created() throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
#Then("^a confirmation message is displayed saying: \"([^\"]*)\"$")
public void a_confirmation_message_is_displayed_saying(String arg1) throws Throwable {
// Express the Regexp above with the code you wish you had
throw new PendingException();
}
}
Action class
#Results({ #Result(name = "success", location = "myFirst.page", type = "tiles") })
#ParentPackage("default")
#Breadcrumb(labelKey = "ca.statcan.icos.sandbox.firstAction")
#SuppressWarnings("serial")
public class MyFirstAction extends HappyfActionSupport {
private List<Employee> employees;
#Autowired
private EmployeeEntityService employeeEntityService;
#Override
public String execute() {
employees = employeeEntityService.getAllEmployee();
if (employees.size() == 0) {
// persist data in memory
final Employee employee1 = new Employee(1, "First", "John", null, "613-222-2222");
employeeEntityService.persistEmployee(employee1);
final Employee employee2 = new Employee(2, "Second", "John", null, "613-222-2223");
employeeEntityService.persistEmployee(employee2);
employees = employeeEntityService.getAllEmployee();
}
return SUCCESS;
}
public List<Employee> getEmployees() {
return employees;
}
}
With this, the embedded tomcat starts correctly and all seems to go well until I try to navigate to a web page. In the StepDefs class, the EmployeeEntityService is injected correctly. However, in the Action class, EmployeeEntityservice is not injected (it remains null).
According to my knowledge, I am setting the parent ApplicationContext for the embedded Tomcat correctly. So why isn't the server using the parent context to get the EmployeeEntityService?
I was stuck with a similar problem and the solution for using an alternative web.xml is simpler than one would dare to think:
2 lines:
Context webContext = tomcat.addWebapp("/yourContextPath", "/web/app/docroot/");
webContext.getServletContext().setAttribute(Globals.ALT_DD_ATTR, "/path/to/custom/web.xml");
Voila! The magic happens in org.apache.catalina.startup.ContextConfig#getWebXmlSource
Disclaimer: Tested on Tomcat 7.0.42

Spring AOP Declarative Transaction Management Not Working

I'm trying to write a simple application to learn how Transaction works in Spring (Declarative AOP Style). I'm inserting one record into customer table and then throwing NullPointerException to see if the inserted data is rolled back or not. But to my surprise it's not rolling back the data. Here is the code
ApplicationContext.xml file
<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-2.5.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
">
<aop:aspectj-autoproxy />
<bean id="BoardingService" class="com.learning.maven.services.BoardingServiceImpl"/>
<tx:advice id="txAdvice" transaction-manager="transactionManager" >
<tx:attributes>
<tx:method name="getUser*" rollback-for="throwable" propagation="REQUIRES_NEW"/>
</tx:attributes>
</tx:advice>
<aop:config>
<aop:pointcut id="boardingServiceOperation" expression="execution(* com.learning.maven.services.BoardingService.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="boardingServiceOperation"/>
</aop:config>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#localhost:1521:XE"/>
<property name="username" value="system"/>
<property name="password" value="Manager"/>
</bean>
<bean id="customerDAO" class="com.learning.maven.dao.CustomerDAOImpl">
<property name="dataSource" ref="dataSource" />
</bean>
This is how I call method
public static void main(String[] args) {
context = new FileSystemXmlApplicationContext("C:\\workspace\\learning\\cxf\\SpringTransaction\\cxf.xml");
BoardingService bean = (BoardingService) context.getBean("BoardingService");
bean.getUser("1");
}
And the BoardingService Class Looks like below
public class BoardingServiceImpl implements BoardingService, ApplicationContextAware {
ApplicationContext context = null;
public String getUser(String id) {
String response = "SUCCESS";
try{
System.out.println("Testing");
CustomerDAO customerDAO = (CustomerDAO) Testing.context.getBean("customerDAO");
Customer c = new Customer();
c.setAge(31);
c.setCustId(1);
c.setName("Jagadeesh");
customerDAO.insert(c);
customerDAO.insert(null);
}
catch(Exception e){
throw new RuntimeException();
}
return response;
}
#Override
public void setApplicationContext(ApplicationContext arg0)
throws BeansException {
this.context = arg0;
}
and the CustomerDAOImpl
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public void insert(Customer customer) {
String sql = "INSERT INTO CUSTOMER (CUST_ID, NAME, AGE) VALUES (?, ?, ?)";
Connection conn = null;
try {
conn = dataSource.getConnection();
PreparedStatement ps = conn.prepareStatement(sql);
ps.setInt(1, customer.getCustId());
ps.setString(2, customer.getName());
ps.setInt(3, customer.getAge());
ps.executeUpdate();
ps.close();
} catch (SQLException e) {
throw new RuntimeException(e);
} finally {
if (conn != null) {
try {
conn.close();
} catch (SQLException e) {}
}
}
}
public Customer findByCustomerId(int custId) {
// TODO Auto-generated method stub
return null;
}
Not sure where am I going wrong. Any Pointers will be of great help.
You have rollback-for "throwable" instead of "Throwable".
P.S. Not sure that you should use REQUIRES_NEW as the default strategy.
update: From DataSourceTransactionManager documentation
Application code is required to retrieve the JDBC Connection via
DataSourceUtils.getConnection(DataSource) instead of a standard
J2EE-style DataSource.getConnection() call. Spring classes such as
JdbcTemplate use this strategy implicitly. If not used in combination
with this transaction manager, the DataSourceUtils lookup strategy
behaves exactly like the native DataSource lookup; it can thus be used
in a portable fashion.
In your case you open connection directly and then Oracle commits transaction on close(this is a feature of Oracle RDBMS).
You can also just omit the rollback-for attribute. Then it will rollback if any RuntimeException occurs.

How to get spring configuration from database

I'm using Eclipse Juno, JDK 7, tomcat 7.0.29, hibernate 4.1.5 and Spring 3.1.2.
I'm trying to load Spring configuration info from database. This is what I could do until now:
WEB.XML
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
/WEB-INF/context-beans.xml
</param-value>
</context-param>
jdbc.properties
jdbc.driver_class=com.microsoft.sqlserver.jdbc.SQLServerDriver
jdbc.url=jdbc:sqlserver://localhost;databaseName=mydbname;
jdbc.username=<my_usr>
jdbc.password=<my_pwd>
context-beans.xml
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:mvc="http://www.springframework.org/schema/mvc"
xmlns:oxm="http://www.springframework.org/schema/oxm"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.1.xsd
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.1.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-3.1.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.1.xsd
http://www.springframework.org/schema/oxm http://www.springframework.org/schema/oxm/spring-oxm-3.1.xsd">
<!-- Configure which package will contain our components -->
<context:component-scan base-package="com.xxx" />
<context:annotation-config />
<mvc:annotation-driven />
<mvc:resources mapping="/static/**" location="/static/" />
<tx:annotation-driven />
<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="persistenceUnitName" value="appPersistenceUnit" />
</bean>
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<bean id="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" p:driverClassName="com.microsoft.sqlserver.jdbc.SQLServerDriver"
p:url="jdbc:sqlserver://localhost;databaseName=appDB" p:username="theUserName" p:password="thePassword" destroy-method="close"/>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate" lazy-init="false" >
<property name="dataSource" ref="dataSource" />
<property name="lazyInit" value="false" />
</bean>
<bean id="appProperties" class="com.xxx.web.util.MyAppPropertyPlaceholderConfigurer">
<property name="nameColumn" value="key" />
<property name="valueColumn" value="value" />
<property name="tableName" value="app_params" />
<property name="whereClause" value="param_type = 'GLOBAL'" />
<property name="jdbcTemplate" ref="jdbcTemplate" />
</bean>
<!-- Files path configuration -->
<mvc:resources mapping="/iconfiles/**" location="file:/${PATH.ICON_FILES}" />
</beans>
Please consider table app_params contains 1 record where key="PATH.ICON_FILES", value="c:/temp/icons/" and param_type="GLOBAL".
MyAppPropertyPlaceholderConfigurer
package com.xxx.web.util;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowCallbackHandler;
public class MyAppPropertyPlaceholderConfigurer extends PropertyPlaceholderConfigurer {
private JdbcTemplate jdbcTemplate;
private String nameColumn;
private String valueColumn;
private String tableName;
private String whereClause;
public MyAppPropertyPlaceholderConfigurer() {
super();
setPlaceholderPrefix("${");
}
#Override
protected void loadProperties(final Properties props) throws IOException {
if (null == props) {
throw new IOException("No properties passed by Spring framework - cannot proceed.");
}
String sql = String.format("SELECT [%s], [%s] FROM [%s] %s", nameColumn, valueColumn, tableName, whereClause);
logger.info("Reading configuration properties from database. Query=" + sql);
try {
jdbcTemplate.query(sql, new RowCallbackHandler() {
#Override
public void processRow(ResultSet rs) throws SQLException {
String name = rs.getString(nameColumn);
String value = rs.getString(valueColumn);
if (null == name || null == value) {
throw new SQLException("Configuration database contains empty data. Name='" + (name == null ? "" : name)
+ "', Value='" + (value == null ? "" : value) + "'.");
}
props.setProperty(name, value);
}
});
} catch (Exception e) {
logger.fatal("There is an error in either 'application.properties' or the configuration database.");
throw new IOException(e);
}
if (props.size() == 0) {
logger.fatal("The configuration database could not be reached or does not contain any properties in '" + tableName
+ "'.");
} else {
logger.info("Application config info loaded from configuration database.");
}
}
#Override
protected String convertPropertyValue(String originalValue) {
if (originalValue.startsWith("!!")) {
// TODO ex: return EncryptUtil.decrypt(originalValue); see org.owasp.esapi.reference.crypto.EncryptedPropertiesUtils
return originalValue;
}
return originalValue;
}
public void setJdbcTemplate(JdbcTemplate newJdbcTemplate) {
this.jdbcTemplate = newJdbcTemplate;
}
public void setNameColumn(String newNameColumn) {
this.nameColumn = newNameColumn;
}
public void setValueColumn(String newValueColumn) {
this.valueColumn = newValueColumn;
}
public void setTableName(String newTableName) {
this.tableName = newTableName;
}
public void setWhereClause(String newWhereClause) {
if (newWhereClause == null || newWhereClause.trim().length() == 0) {
this.whereClause = "";
} else {
if (newWhereClause.trim().toUpperCase().startsWith("WHERE ")) {
this.whereClause = newWhereClause;
} else {
this.whereClause = "WHERE " + newWhereClause;
}
}
}
}
Doing it this way works as expected and I have variable ${PATH.ICON_FILES} properly resolved.
However, I don't want to have my dataSource bean with username, password and all stuff hard coded on the XML file. I would like to load it from another property file, preferentially encrypted.
How do I get this done?
I already tried to add another PropertyPlaceholderConfigurer with jdbc configuration (plain text at this time) by adding the code below into context-beans.xml:
<bean id="jdbcConfigurer" name="jdbcConfigurer" class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<value>classpath:jdbc.properties</value>
</list>
</property>
</bean>
Then I changed dataSource bean to read from there:
<bean id="dataSource" name="dataSource" class="org.apache.tomcat.dbcp.dbcp.BasicDataSource" p:driverClassName="${jdbc.driver_class}"
p:url="${jdbc.url}" p:username="${jdbc.username}" p:password="${jdbc.password}" destroy-method="close" />
When I try to run I get the following error:
[2012-10-10 11:33:48,744] WARN (SQLErrorCodesFactory.java:227) - Error while extracting database product name - falling back to empty error codes
org.springframework.jdbc.support.MetaDataAccessException: Could not get Connection for extracting meta data; nested exception is org.springframework.jdbc.CannotGetJdbcConnectionException: Could not get JDBC Connection; nested exception is org.apache.tomcat.dbcp.dbcp.SQLNestedException: Cannot load JDBC driver class '${jdbc.driver_class}'
Any idea what I'm doing wrong here? Looks like it is instantiating MyAppPropertyPlaceholderConfigurer prior to getting the values from the regular PropertyPlaceholderConfigurer...
Thanks.

Injection of the sessionFactory not working

I'm new with Spring and I want to inject the sessionFactory and its not working at all. I'm starting a web server Jetty and then I load the context. After i start a GWT web application, I make a call on the server side and I try to get some info but I get a null pointer. There is no error at all so it make it difficult to know where the problem is. I know its suppose to work because I saw it working on a project I worked on some times ago. Any help will be appreciate. (Sorry for my possibly bad english)
Here is the context.xml :
<?xml version="1.0" encoding="UTF-8" ?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:security="http://www.springframework.org/schema/security"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema
/context/spring-context-3.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema
/tx/spring-tx-3.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema
/aop/spring-aop-3.0.xsd
http://www.springframework.org/schema/security http://www.springframework.org/schema
/security/spring-security-3.0.xsd">
<!-- Standard spring initialization -->
<context:component-scan base-package="com.test">
</context:component-scan>
<tx:annotation-driven transaction-manager="txManager"/>
<!-- Connection to the database-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-
method="close">
<property name="driverClassName" value="com.mysql.jdbc.Driver" />
<property name="url" value="jdbc:mysql://localhost:3306/test" />
<property name="username" value="root" />
<property name="password" value="123456789" />
</bean>
<!-- Hibernate session factory-->
<bean id="jpaSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="packagesToScan" value="com.domain"/>
<property name="namingStrategy" >
<bean class="org.hibernate.cfg.ImprovedNamingStrategy" />
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5Dialect</prop>
<prop key="show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
</bean>
<!-- Hibernate session factory -->
<bean id="txManager"
class="org.springframework.orm.hibernate3.HibernateTransactionManager">
<property name="sessionFactory" ref="jpaSessionFactory" />
</bean>
</beans>
Here is the main :
public static void main(String[] args) {
ContextHandlerCollection contexts = new ContextHandlerCollection();
contexts.setHandlers(new Handler[]
{ new AppContextBuilder().buildWebAppContext()});
final JettyServer jettyServer = new JettyServer();
jettyServer.setHandler(contexts);
Runnable runner = new Runnable() {
#Override
public void run() {
new ServerRunner(jettyServer);
}
};
EventQueue.invokeLater(runner);
new ClassPathXmlApplicationContext("context.xml");
}
Here is the class Test where I want the injection :
#Component("test")
public class TEST{
#Resource(name="jpaSessionFactory")
private SessionFactory sessionFactory;
#SuppressWarnings("unchecked")
#Transactional(readOnly = true)
public List<Personne> getPersonnes() {
Session s = sessionFactory.getCurrentSession();
Query query = s.createQuery("from Person");
return query.list();
}
}
Here is the server side from the application (not shown completely)
/*** The server side implementation of the RPC service.
*/
#SuppressWarnings("serial")
public class GreetingServiceImpl extends RemoteServiceServlet implements
GreetingService {
#Resource
private TEST t;
public String greetServer(String input) throws IllegalArgumentException {
// Verify that the input is valid.
if (!FieldVerifier.isValidName(input)) {
// If the input is not valid, throw an IllegalArgumentException
back to
// the client.
throw new IllegalArgumentException(
"Name must be at least 4 characters long");
}
t.getPersons(); // NULL pointer here
.........................
The MySQL tables are created like it should, so all the scanning seems to work.
Thanks
Bob
This is because the GreetingServiceImpl class is not created by spring - it is servlet that is initialized by the container directly. Follow the instructions in this article to fix the issue. I have copied the relevant code from the article.
#Override
public void init() throws ServletException {
super.init();
final WebApplicationContext ctx =
WebApplicationContextUtils.getWebApplicationContext(getServletContext());
if (ctx == null) {
throw new IllegalStateException("No Spring web application context found");
}
ctx.getAutowireCapableBeanFactory().autowireBeanProperties(this,
AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE, true);
}

Resources