Spring and Hibernate 4: get is not valid without active transaction - spring

I am using Spring annotations and hibernate to create a DAO. I am using Spring 3.2.5 and hibernate 4.3.3. For some reason I keep getting this exception:
org.hibernate.HibernateException: get is not valid without active transaction
Here is the relevant portion of my spring app context:
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- Pick up the HibernateHouseDAO spring bean -->
<context:component-scan base-package="jinvestor.jhouse.download" />
<bean id="sessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="annotatedClasses">
<list>
<value>jinvestor.jhouse.core.HouseEntity</value>
</list>
</property>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.current_session_context_class">thread</prop>
<!-- <prop key="hibernate.transaction.factory_class">org.hibernate.transaction.JDBCTransactionFactory</prop> -->
</props>
</property>
</bean>
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${dataSource.driver}" />
<property name="url" value="${dataSource.url}" />
<property name="username" value="${dataSource.username}" />
<property name="password" value="${dataSource.password}" />
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource" />
</bean>
This is my DAO:
#Repository("dao")
#Profile("mysql")
#Transactional
public class HibernateHouseDAO implements HouseDAO {
private final SessionFactory sessionFactory;
#Autowired
public HibernateHouseDAO(SessionFactory sessionFactory) {
this.sessionFactory = sessionFactory;
}
#Override
public House load(long id) {
// this throws a nosuch method error for openSession.
// Session session = SessionFactoryUtils.getSession(sessionFactory, false);
// this throws an error on the lack of a transaction.
Session session = sessionFactory.getCurrentSession();
HouseEntity entity = (HouseEntity) session.get(HouseEntity.class, id);
return House.fromEntity(entity);
}
#Override
public void save(House house) {
sessionFactory.getCurrentSession().save(new HouseEntity(house));
}
BTW the #Transactional is spring's, not javax.transaction. Here is my unit test:
// MT stands for manual test
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:/applicationContext.xml"})
#ActiveProfiles(profiles={"test","mysql"})
public class HibernateHouseDAOMT extends HouseDAOTest {
#Autowired
private HouseDAO dao;
#Override
public HouseDAO getDao() {
return dao;
}
}
Here is my SQL schema in case you need to know it:
create table homes (zpid BIGINT PRIMARY KEY NOT NULL, address VARCHAR(200) NOT NULL,squareFeet INT UNSIGNED,soldPrice INT UNSIGNED, latitude INT,longitude INT,lastSoldDate DATE, yearBuilt YEAR,acres FLOAT UNSIGNED,beds TINYINT UNSIGNED,baths TINYINT UNSIGNED, INDEX (address)) ENGINE = 'INNODB';
Also, all of my code is on github in case you want to see something I did not copy here. This is the project root on github:
https://github.com/msknapp/JInvestor/tree/master/JHouse/jhouse.download
Please help me get this to work.
===================
Update:
Switching to Hibernate Transaction Manager:
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
</bean>
and here is the exception:
java.lang.IllegalStateException: Failed to load ApplicationContext
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:99)
at org.springframework.test.context.TestContext.getApplicationContext(TestContext.java:122)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.injectDependencies(DependencyInjectionTestExecutionListener.java:109)
at org.springframework.test.context.support.DependencyInjectionTestExecutionListener.prepareTestInstance(DependencyInjectionTestExecutionListener.java:75)
at org.springframework.test.context.TestContextManager.prepareTestInstance(TestContextManager.java:312)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.createTest(SpringJUnit4ClassRunner.java:211)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner$1.runReflectiveCall(SpringJUnit4ClassRunner.java:288)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.methodBlock(SpringJUnit4ClassRunner.java:284)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'transactionManager' defined in class path resource [applicationContext.xml]: Invocation of init method failed; nested exception is java.lang.NoSuchMethodError: org.hibernate.engine.spi.SessionFactoryImplementor.getConnectionProvider()Lorg/hibernate/service/jdbc/connections/spi/ConnectionProvider;
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:628)
at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:120)
at org.springframework.test.context.support.AbstractGenericContextLoader.loadContext(AbstractGenericContextLoader.java:60)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.delegateLoading(AbstractDelegatingSmartContextLoader.java:100)
at org.springframework.test.context.support.AbstractDelegatingSmartContextLoader.loadContext(AbstractDelegatingSmartContextLoader.java:248)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContextInternal(CacheAwareContextLoaderDelegate.java:64)
at org.springframework.test.context.CacheAwareContextLoaderDelegate.loadContext(CacheAwareContextLoaderDelegate.java:91)
... 25 more
Caused by: java.lang.NoSuchMethodError: org.hibernate.engine.spi.SessionFactoryImplementor.getConnectionProvider()Lorg/hibernate/service/jdbc/connections/spi/ConnectionProvider;
at org.springframework.orm.hibernate4.SessionFactoryUtils.getDataSource(SessionFactoryUtils.java:90)
at org.springframework.orm.hibernate4.HibernateTransactionManager.afterPropertiesSet(HibernateTransactionManager.java:335)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509)
... 40 more
based on this, maybe I am missing a dependency in my pom, or have a bad dependency. I will try to find out...
I am using mysql-connector-java version 5.1.29, perhaps that is incompatible?

You're using Spring 3.2.5, and it's not compatible with the latest Hibernate 4.3.3 version that you're using. Hibernate 4.3 indeed decided to change the package of the ConnectionProvider returned by SessionFactoryImplementor.getConnectionProvider(). Use the latest Spring version, or use Hibernate 4.2, and it should run better.

Related

Error creating bean with name 'sqlSessionFactory' ... Invocation of init method failed; nested exception is java.lang.NullPointerException

I'm trying to integrate spring-mybatis in my application. I'm using spring 4.1.4 and mybatis 3.2.8 java 7 and the server is WebSphere Application Server Liberty. I'm using a spring java configuration class. This error is showing only when I'm deploying the war file, if I'm using Eclipse to deploy the project everything is ok. Deploying in Tomcat 8 is working too.
#Configuration
#MapperScan("x.y.z.mappers")
#PropertySource("classpath:/x/y/z/data_source.properties")
#EnableTransactionManagement
public class DataAccessConfiguration {
#Autowired
private Environment env;
#Bean
public DataSource dataSource() {
DriverManagerDataSource dataSource = new DriverManagerDataSource();
dataSource.setDriverClassName(env.getProperty("driver"));
dataSource.setUrl(env.getProperty("url"));
dataSource.setUsername(env.getProperty("user"));
dataSource.setPassword(env.getProperty("password"));
return dataSource;
}
#Bean
public DataSourceTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
#Bean
public SqlSessionFactoryBean sqlSessionFactory() throws Exception {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
sessionFactory.setDataSource(dataSource());
sessionFactory.setTypeAliasesPackage("x.y.z.portal.model");
return sessionFactory;
}
}
I got this stacktrace
Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'sqlSessionFactory' defined in a.b.c.DataAccessConfiguration: Invocation of init method failed; nested exception is java.lang.NullPointerException
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1566)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:476)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:303)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:299)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1127)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1051)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:949)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireByType(AbstractAutowireCapableBeanFactory.java:1280)
... 60 more
Caused by: java.lang.NullPointerException
at java.io.FilterInputStream.read(FilterInputStream.java:133)
at sun.nio.cs.StreamDecoder.readBytes(StreamDecoder.java:283)
at sun.nio.cs.StreamDecoder.implRead(StreamDecoder.java:325)
at sun.nio.cs.StreamDecoder.read(StreamDecoder.java:177)
at java.io.InputStreamReader.read(InputStreamReader.java:184)
at java.io.BufferedReader.fill(BufferedReader.java:154)
at java.io.BufferedReader.readLine(BufferedReader.java:317)
at java.io.BufferedReader.readLine(BufferedReader.java:382)
at org.apache.ibatis.io.DefaultVFS.list(DefaultVFS.java:93)
at org.apache.ibatis.io.VFS.list(VFS.java:193)
at org.apache.ibatis.io.ResolverUtil.find(ResolverUtil.java:216)
at org.apache.ibatis.type.TypeAliasRegistry.registerAliases(TypeAliasRegistry.java:127)
at org.mybatis.spring.SqlSessionFactoryBean.buildSqlSessionFactory(SqlSessionFactoryBean.java:399)
at org.mybatis.spring.SqlSessionFactoryBean.afterPropertiesSet(SqlSessionFactoryBean.java:355)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1625)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1562)
Instead try this to integrate your application with mybatis. Add below code to spring-dispatcher-servlet.xml.
<context:property-placeholder location="x/y/z/data_source.properties"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName"><value>${database.driver}</value></property>
<property name="url"><value>${database.url}</value></property>
<property name="username"><value>${database.username}</value></property>
<property name="password"><value>${database.password}</value></property>
<property name="maxActive"><value>${database.maxactiveconnections}</value></property>
<property name="maxIdle"><value>${database.idleconnections}</value></property>
<property name="initialSize"><value>${database.initialSize}</value></property>
</bean>
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configLocation" value="/WEB-INF/mybatis-config.xml"/>
</bean>
<bean id="Dao" class="org.mybatis.spring.mapper.MapperFactoryBean">
<property name="sqlSessionFactory" ref="sqlSessionFactory"/>
<property name="mapperInterface" value="com.dao.Dao" />
</bean>

Spring: Can't move #Transactioanl annotation from DAO to Service layer

It the Transactional annotation is in the DAO layer it works, if I move it to the service layer, I get exception:
Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.adam.czibere.RestAPIController]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch
Here is my code:
CatalogDAOInterface:
public interface CatalogDAOInterface {
public List<Product> getAllProduct();
public List<Category> getAllCategories() ;
public List<Media> getAllMedias();
}
CatalogDAO:
#Repository
#SuppressWarnings({"unchecked", "rawtypes"})
public class CatalogDAO implements CatalogDAOInterface {
#Autowired private SessionFactory sessionFactory;
#Override
public List<Product> getAllProduct() {
Session session = sessionFactory.getCurrentSession();
List products = session.createQuery("from Product").list();
return products;
}
#Override
public List<Category> getAllCategories() {
Session session = sessionFactory.getCurrentSession();
List products = session.createQuery("from Category").list();
return products;
}
#Override
public List<Media> getAllMedias() {
Session session = sessionFactory.getCurrentSession();
List medias = session.createQuery("from Media").list();
return medias;
}
}
CatalogServiceInterface:
public interface CatalogServiceInterface {
public List<Category> getAllCategories();
public List<Product> getAllProducts();
public List<Media> getAllMedias();
}
CatalogService:
#Service
public class CatalogService implements CatalogServiceInterface{
#Autowired
private CatalogDAO catalogDAO;
#Transactinal
#Override
public List<Product> getAllProducts() {
return catalogDAO.getAllProduct();
}
#Transactinal
#Override
public List<Category> getAllCategories() {
return catalogDAO.getAllCategories();
}
#Transactinal
#Override
public List<Media> getAllMedias() {
return catalogDAO.getAllMedias();
}
}
servlet-context.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:mvc="http://www.springframework.org/schema/mvc"
xmlns:beans="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context" xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc-3.2.xsd
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-3.2.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.2.xsd">
<!-- Enable #Controller annotation support -->
<mvc:annotation-driven />
<!-- Handles HTTP GET requests for /resources/** by efficiently serving
up static resources in the ${webappRoot}/resources directory -->
<mvc:resources mapping="/resources/**" location="/resources/" />
<!-- Resolves views selected for rendering by #Controllers to .jsp resources
in the /WEB-INF/views directory -->
<bean
class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="prefix" value="/WEB-INF/views/" />
<property name="suffix" value=".jsp" />
</bean>
<context:component-scan base-package="com.adam.czibere" />
<!-- <bean id="myDataSource" 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/pizzashop" /> -->
<!-- <property name="username" value="root" /> -->
<!-- <property name="password" value="czadam" /> -->
<!-- <property name="validationQuery" value="SELECT 1" /> -->
<!-- </bean> -->
<bean id="myDataSource" class="org.apache.commons.dbcp.BasicDataSource"
destroy-method="close">
<property name="driverClassName" value="net.sourceforge.jtds.jdbc.Driver" />
<property name="url" value="jdbc:jtds:sqlserver://something" />
<property name="username" value="something" />
<property name="password" value="something" />
<property name="validationQuery" value="SELECT 1" />
</bean>
<!-- Hibernate Session Factory -->
<bean id="mySessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="myDataSource" />
<property name="packagesToScan">
<array>
<value>com.adam.czibere</value>
</array>
</property>
<property name="hibernateProperties">
<value>
hibernate.dialect=org.hibernate.dialect.MySQLDialect
</value>
</property>
</bean>
<!-- Hibernate Transaction Manager -->
<bean id="transactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="mySessionFactory" />
</bean>
<!-- Activates annotation based transaction management -->
<tx:annotation-driven transaction-manager="transactionManager" />
</beans>
The stack trace:
exception
javax.servlet.ServletException: Servlet.init() for servlet appServlet threw exception
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:724)
root cause
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'catalogAPIController' defined in file [C:\Users\czadam\Documents\workspace 2.0\.metadata\.plugins\org.eclipse.wst.server.core\tmp1\wtpwebapps\SalesWizard\WEB-INF\classes\com\adam\czibere\CatalogAPIController.class]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.adam.czibere.CatalogAPIController]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch
org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:288)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:631)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:588)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:645)
org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:508)
org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:449)
org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:133)
javax.servlet.GenericServlet.init(GenericServlet.java:160)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:724)
root cause
org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [com.adam.czibere.CatalogAPIController]: Illegal arguments for constructor; nested exception is java.lang.IllegalArgumentException: argument type mismatch
org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:158)
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:110)
org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:280)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:631)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:588)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:645)
org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:508)
org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:449)
org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:133)
javax.servlet.GenericServlet.init(GenericServlet.java:160)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:724)
root cause
java.lang.IllegalArgumentException: argument type mismatch
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
java.lang.reflect.Constructor.newInstance(Constructor.java:526)
org.springframework.beans.BeanUtils.instantiateClass(BeanUtils.java:147)
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:110)
org.springframework.beans.factory.support.ConstructorResolver.autowireConstructor(ConstructorResolver.java:280)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.autowireConstructor(AbstractAutowireCapableBeanFactory.java:1035)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:939)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:485)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:456)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:294)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:225)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:291)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:193)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:585)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:913)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:464)
org.springframework.web.servlet.FrameworkServlet.configureAndRefreshWebApplicationContext(FrameworkServlet.java:631)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:588)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:645)
org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:508)
org.springframework.web.servlet.FrameworkServlet.initServletBean(FrameworkServlet.java:449)
org.springframework.web.servlet.HttpServletBean.init(HttpServletBean.java:133)
javax.servlet.GenericServlet.init(GenericServlet.java:160)
org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:472)
org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:99)
org.apache.catalina.valves.AccessLogValve.invoke(AccessLogValve.java:936)
org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:407)
org.apache.coyote.http11.AbstractHttp11Processor.process(AbstractHttp11Processor.java:1004)
org.apache.coyote.AbstractProtocol$AbstractConnectionHandler.process(AbstractProtocol.java:589)
org.apache.tomcat.util.net.JIoEndpoint$SocketProcessor.run(JIoEndpoint.java:312)
java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1145)
java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:615)
java.lang.Thread.run(Thread.java:724)
Part of My Controller:
#Controller
#RequestMapping(value = "api", produces = "application/json")
public class CatalogAPIController {
CatalogService catalogService;
private static final int BUFFER_SIZE = 4096;
#Autowired
public CatalogAPIController(CatalogService catalogService) {
this.catalogService = catalogService;
}
// get all categories
#RequestMapping(value = "category/all", produces = "application/json;charset=UTF-8")
#ResponseBody
public String getAllCategories() {
JSONArray categoryArray = new JSONArray();
for (Category cat : catalogService.getAllCategories()) {
JSONObject categoryJSON = new JSONObject();
try {
categoryJSON.put("id", cat.getId());
categoryJSON.put("name", cat.getName());
categoryJSON.put("imageMediaID", cat.getImageMediaID());
categoryJSON.put("parentID", cat.getParent().getId());
// Media
JSONArray mediaArray = new JSONArray();
for (Media item : cat.getMedias()) {
if (item != null) {
mediaArray.put(item.getId());
}
}
categoryJSON.put("mediaIDs", mediaArray);
categoryJSON.put("modifiedDate", cat.getModifiedDate());
categoryArray.put(categoryJSON);
} catch (JSONException e) {
e.printStackTrace();
return "Error: " + e.getMessage();
}
}
return categoryArray.toString();
}
}
When Spring is applying the #Transactional annotation internally, it creates a proxy class which wraps your service class.
So when your service bean is created in your application context, you are getting an object that is not of type CatalogService but some Proxy$1 class.
This Proxy$1 class will not extend CatalogService but it will implement CatalogServiceInterface. Therefore, when your CatalogAPIController bean gets created, it attempts to call its constructor with your Proxy$1 object which is the wrong type as your constructor expects a class.
So if you were to change your controller to use the interface instead of the implementation, then I believe your problems will disappear. This is because Proxy$1 DOES implement CatalogServiceInterface.
The moral of the story: ALWAYS use the interface if you reference your implementation (for if you ever decide to provide a different implementation (e.g. CatalogService2 which also implements CatalogServiceInterface, you can only plug that into your CatalogAPIController if its constructor is using the interface rather than the class (and essentially this is what's happening when you specify #Transactional.
Hope that makes sense.
two thing caught my attention
1.
#Transactinal
is it a typo or are you importing another annotation, it should be #Transactional
2.
why aren't you using the interfaces if you're already defining them?
instead of
#Autowired
public CatalogAPIController(CatalogService catalogService) {
this.catalogService = catalogService;
}
change it to
#Autowired
public CatalogAPIController(CatalogServiceInterface catalogService) {
this.catalogService = catalogService;
}
same applies to dao interface.
I don't understand the relation between moving transactional from one place to the other. See if that helps
This is what I can think of with the details you've provided. I believe you don't have the CGLIB libraries on your classpath. As such, for Spring to apply #Transactional behavior, it proxies your annotated class with JDK proxies. JDK proxies use interfaces, they cannot proxy base classes. As such, the direct superclass of a proxy is java.lang.reflect.Proxy.
In this case, your CatalogService bean will be wrapped in a proxy whose class is something like Proxy$1. When Spring tries to instantiate your #Controller class, CatalogAPIController, through reflection using the constructor
#Autowired
public CatalogAPIController(CatalogService catalogService) {
this.catalogService = catalogService;
}
it will fail because the argument passed to the Constructor#newInstance(Object...) method will not match the parameter type CatalogService since Proxy$1 is not a sub type of CatalogService.
The reason this didn't happen when you were annotating the DAO, I believe is that your DAO class is not on the component-scan package that applied #Transactional behavior. So it might have appeared as though the #Transactional was working but it wasn't. Because #Transactional wasn't working, no proxy was created and therefore Spring didn't complain about injecting this field
#Autowired
private CatalogDAO catalogDAO;
in your service class.
One possible solution is to do what Luis recommended and change your parameter types to the interface as JDK proxies to implement the interfaces, ie. the interfaces are supertypes of the Proxy$1 class instance generated to wrap your bean.
Another solution is to provide the CGLIB jars on your classpath. Spring will detect them and use them. It will then be able to proxy your class by base class instead of interface. You can find the libraries here.
Don't forget to tell Spring to proxy the target class with
<tx:annotation-driven transaction-manager="transactionManager" proxy-target-class="true" />

Struts2; keeping a session open for StrutsSpringTestCase JUnit tests

My project architecture is Struts2 with Spring integration and JPA/Hibernate. StrutsSpringTestCase base class is utilized for JUnit integration tests.
Under normal circumstances, the following configuration in web.xml keeps a single session open from start to finish of each request:
<filter>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<filter-class>org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>
<filter-mapping>
<filter-name>Spring OpenEntityManagerInViewFilter</filter-name>
<url-pattern>/*</url-pattern>
</filter-mapping>
As a result, all lazy loading works fine in all services. For example:
#Override
public Person find(int id) {
Person person = personDao.find(id);
// Take care of lazy loading before detaching the object for
// the view layer...
person.getGender().getCode();
// Detach the object so that it can be used for data transfer
// (as a DTO) without causing JPA issues and errors...
getEntityManager().detach(person);
return person;
}
Now... issues arise when I try to run the integration tests, which are independent of the OpenEntityManagerInViewFilter configuration in web.xml.
What happens is that since there is no session being kept open from start to finish of each request, lazy loading statements like "person.getGender().getCode()" don't work any longer, and I get the "could not initialize proxy - no Session" errors.
One solution I'm aware of is to force the #Transactional annotation upon the service methods that are having the lazy-loading issues, which will result in a session being open from start to finish of the method call. I tested it and it fixed the problem:
#Transactional
#Override
public Person find(int id) {
Person person = personDao.find(id);
// Take care of lazy loading before detaching the object for
// the view layer...
person.getGender().getCode();
// Detach the object so that it can be used for data transfer
// (as a DTO) without causing JPA issues and errors...
getEntityManager().detach(person);
return person;
}
However, this could be overkill as the method doesn't need a transaction under normal circumstances. I'm wondering if there is another solution that doesn't require to compromise on the service side.
Is there something I can add to my test classes (which extend StrutsSpringTestCase) to keep the session open? Or is there perhaps an elegant configuration solution on the Spring or JUnit side?
Here is my Spring configuration file - 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:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-2.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-2.0.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.0.xsd"
default-dependency-check="all"
default-lazy-init="false"
default-autowire="byName">
<!-- *************** MAIN CONFIGURATION SECTION *************** -->
<!-- Bean post-processor for JPA annotations. -->
<!-- Make the Spring container act as a JPA container and inject an EnitityManager from
the EntityManagerFactory. -->
<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"
autowire="no"
dependency-check="none" />
<!-- ** Data Source Configuration ** -->
<bean id="dataSource"
class="com.mchange.v2.c3p0.ComboPooledDataSource"
destroy-method="close"
autowire="no"
dependency-check="none">
<!-- Database configuration: -->
<property name="driverClass" value="com.mysql.jdbc.Driver" />
<property name="jdbcUrl" value="jdbc:mysql://localhost/**********" />
<property name="user" value="**********" />
<property name="password" value="**********" />
<!-- C3P0 pooling properties configuration: -->
<property name="acquireIncrement" value="4" />
<property name="initialPoolSize" value="4" />
<property name="minPoolSize" value="4" />
<property name="maxPoolSize" value="20" />
<property name="maxIdleTime" value="600" />
<property name="maxConnectionAge" value="1800" />
</bean>
<!-- ** JPA Vendor Selection ** -->
<bean id="jpaVendorAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter"
autowire="no"
dependency-check="none" />
<!-- ** JPA Vendor and Entity Manager Configuration ** -->
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"
autowire="no"
dependency-check="none">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter" ref="jpaVendorAdapter" />
<property name="jpaProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</prop>
<!-- Have the JPA vendor manage the database schema: -->
<prop key="hibernate.hbm2ddl.auto">create</prop>
<prop key="hibernate.cache.use_second_level_cache">true</prop>
<prop key="hibernate.cache.use_query_cache">true</prop>
<prop key="hibernate.cache.region.factory_class">org.hibernate.cache.ehcache.EhCacheRegionFactory</prop>
<prop key="hibernate.max_fetch_depth">4</prop>
<prop key="hibernate.jdbc.batch_size">1000</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.format_sql">false</prop>
</props>
</property>
</bean>
<!-- ** Transaction Manager Configuration ** -->
<bean id="transactionManager"
class="org.springframework.orm.jpa.JpaTransactionManager"
autowire="no"
dependency-check="none">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
<!-- ** Transaction Annotation Configuration; classes/functions with #Transactional will
get a framework transaction. ** -->
<tx:annotation-driven transaction-manager="transactionManager" />
<!-- **** DETAILED SERVICE BEAN CONFIGURATION WAS TAKEN OUT TO SHORTEN THE FILE **** -->
</beans>
I would appreciate any pointers.
EDIT:
To make things a bit more visual, the following test generates an exception when the service method in question encounters lazy loading and the service method is not annotated with #Transactional, but works just fine when the service method is annotated with #Transactional.
public class ActionTest extends CustomActionTestBase {
public ActionTest() {
super("/web/someAction"); // the action to test
}
#Override
public void testHelperActionLoggedIn() throws Exception {
procApplyContinualSessionForAdmin(); // the numerous steps to get logged in
procExecuteAction(
helpGetPrimaryActionURI(), // use the action URI set by the constructor above
helpPrepareActionParams( ) // no parameters are passed to this action
);
procConfirmOutcome(ActionSupport.SUCCESS,0,0,0,false);
}
}
Note: CustomActionTestBase extends StrutsSpringTestCase (which in turn extends some JUnit stuff). I needed CustomActionTestBase due to some heavy test case customization/automation.
EDIT:
I also tried adding #Transactional to the "testHelperActionLoggedIn()" test method itself, which didn't change the outcome.
EDIT:
Additionally, I tried to make things more Spring-specific (as instructed by Aleksandr M) by annotating with #RunWith, #ContextConfiguration, and #Test.
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class ActionTest extends CustomActionTestBase {
public ActionTest() {
super("/web/someAction"); // the action to test
}
#Test
#Override
public void testHelperActionLoggedIn() throws Exception {
procApplyContinualSessionForAdmin(); // the numerous steps to get logged in
procExecuteAction(
helpGetPrimaryActionURI(), // use the action URI set by the constructor above
helpPrepareActionParams( ) // no parameters are passed to this action
);
procConfirmOutcome(ActionSupport.SUCCESS,0,0,0,false);
}
}
It resulted in an exception that showed up in the JUnit Failure Trace - there was no exception output in the console for whatever reason.
Exception details:
java.lang.NullPointerException
at org.apache.struts2.StrutsTestCase.getActionMapping(StrutsTestCase.java:196)
at org.apache.struts2.StrutsTestCase.getActionMapping(StrutsTestCase.java:206)
at com.mycompany.utils.test.CustomActionTestBase.examineActionMapping(CustomActionTestBase.java:402)
at com.mycompany.utils.test.CustomActionTestBase.procExecuteAction(CustomActionTestBase.java:158)
at com.mycompany.utils.test.CustomActionTestBase.execLoginActionForAdmin(CustomActionTestBase.java:505)
at com.mycompany.utils.test.CustomActionTestBase.procApplyContinualSessionForAdmin(CustomActionTestBase.java:106)
at com.mycompany.actions.web.ActionTest.testHelperActionLoggedIn(ActionTest.java:30)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source)
at java.lang.reflect.Method.invoke(Unknown Source)
at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:47)
at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:44)
at org.junit.internal.runners.statements.InvokeMethod.evaluate(InvokeMethod.java:17)
at org.springframework.test.context.junit4.statements.RunBeforeTestMethodCallbacks.evaluate(RunBeforeTestMethodCallbacks.java:74)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:82)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:240)
at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:50)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:238)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:63)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:236)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:53)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:229)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:70)
at org.junit.runners.ParentRunner.run(ParentRunner.java:309)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:180)
at org.eclipse.jdt.internal.junit4.runner.JUnit4TestReference.run(JUnit4TestReference.java:50)
at org.eclipse.jdt.internal.junit.runner.TestExecution.run(TestExecution.java:38)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:467)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.runTests(RemoteTestRunner.java:683)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.run(RemoteTestRunner.java:390)
at org.eclipse.jdt.internal.junit.runner.RemoteTestRunner.main(RemoteTestRunner.java:197)
It looks like it's having trouble with getting the action mapping, which it didn't before.
You can put #Transactional annotation over test method and you need to run your tests with spring in order it could find #Transactional annotation. To use JUnit4 in Struts2 tests you need to extend StrutsSpringJUnit4TestCase. So your test class should look something like that:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations={"classpath:applicationContext.xml"})
public class ActionTest extends StrutsSpringJUnit4TestCase {
#Transactional
#Test
public void testHelperActionLoggedIn() throws Exception {
// ...
}
}
Note: If you need to obtain ActionProxy you can get it by calling getActionProxy method. You probably need to create new session map for it and then you can call execute.
ActionProxy actionProxy = getActionProxy("/action");
Map<String, Object> sessionMap = new HashMap<String, Object>();
actionProxy.getInvocation().getInvocationContext().setSession(sessionMap);
actionProxy.execute();
BUT if you don't need reference to ActionProxy then you can use executeAction method to execute action in this way you don't need to create new session map.
executeAction("/action");

load application context for junit hibernate tests inside spring

I've got a properly defined spring configuration XML file, which imports some other XML files. THe test should read/write/delete records from MySQL database. I've got a problem with hibernate - the test is unable to access the database and hibernate throws following exception:
Unknown service requested [org.hibernate.stat.spi.StatisticsImplementor];
nested exception is org.hibernate.service.UnknownServiceException:
Unknown service requested [org.hibernate.stat.spi.StatisticsImplementor]
This is my test class:
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(value = "classpath:*.xml")
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional
public class JukeboxTest {
#Autowired
private ApplicationContext applicationContext;
private Jukebox jukebox;
private SessionFactory sessionFactory;
private Session session = null;
#BeforeClass
public static void setUpClass() {
}
#AfterClass
public static void tearDownClass() {
}
#Before
public void setUp() {
jukebox = (Jukebox) applicationContext.getBean("metal_jukebox");
sessionFactory = (SessionFactory) applicationContext.getBean("sessionFactory");
session = sessionFactory.openSession();
System.out.println(jukebox.getName());
}
#After
public void tearDown() {
session.close();
sessionFactory.close();
}
#Test
#Transactional
public void testGetName() {
assertEquals("Metal Jukebox", jukebox.getName());
}
This is my hibernate config file:
<?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"
xsi:schemaLocation="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.xsd">
<bean id="sessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.MySQLDialect</prop>
<prop key="hibernate.show_sql">true</prop>
<prop key="hibernate.hbm2ddl.auto">update</prop>
</props>
</property>
<property name="annotatedClasses">
<list>
<value>com.blogspot.symfonyworld.lyricsbase.model.Song</value>
</list>
</property>
</bean>
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"/>
</beans>
the system.out line properly displays value defined in the bean XML, so the configuration is ok. I guess the annotations are somehow wrong, but I don't know what to fix, since the exception tells me nothing.
This is the exception stack trace:
org.springframework.orm.hibernate4.HibernateSystemException: Unknown service requested [org.hibernate.stat.spi.StatisticsImplementor]; nested exception is org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.stat.spi.StatisticsImplementor]
at org.springframework.orm.hibernate4.SessionFactoryUtils.convertHibernateAccessException(SessionFactoryUtils.java:185)
at org.springframework.orm.hibernate4.HibernateTransactionManager.convertHibernateAccessException(HibernateTransactionManager.java:594)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:495)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.processRollback(AbstractPlatformTransactionManager.java:846)
at org.springframework.transaction.support.AbstractPlatformTransactionManager.rollback(AbstractPlatformTransactionManager.java:823)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener$TransactionContext.endTransaction(TransactionalTestExecutionListener.java:588)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.endTransaction(TransactionalTestExecutionListener.java:297)
at org.springframework.test.context.transaction.TransactionalTestExecutionListener.afterTestMethod(TransactionalTestExecutionListener.java:192)
at org.springframework.test.context.TestContextManager.afterTestMethod(TestContextManager.java:396)
at org.springframework.test.context.junit4.statements.RunAfterTestMethodCallbacks.evaluate(RunAfterTestMethodCallbacks.java:91)
at org.springframework.test.context.junit4.statements.SpringRepeat.evaluate(SpringRepeat.java:72)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:231)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.runChild(SpringJUnit4ClassRunner.java:88)
at org.junit.runners.ParentRunner$3.run(ParentRunner.java:231)
at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:60)
at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:229)
at org.junit.runners.ParentRunner.access$000(ParentRunner.java:50)
at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:222)
at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:28)
at org.springframework.test.context.junit4.statements.RunBeforeTestClassCallbacks.evaluate(RunBeforeTestClassCallbacks.java:61)
at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:30)
at org.springframework.test.context.junit4.statements.RunAfterTestClassCallbacks.evaluate(RunAfterTestClassCallbacks.java:71)
at org.junit.runners.ParentRunner.run(ParentRunner.java:300)
at org.springframework.test.context.junit4.SpringJUnit4ClassRunner.run(SpringJUnit4ClassRunner.java:174)
at org.apache.maven.surefire.junit4.JUnit4TestSet.execute(JUnit4TestSet.java:53)
at org.apache.maven.surefire.junit4.JUnit4Provider.executeTestSet(JUnit4Provider.java:123)
at org.apache.maven.surefire.junit4.JUnit4Provider.invoke(JUnit4Provider.java:104)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:616)
at org.apache.maven.surefire.util.ReflectionUtils.invokeMethodWithArray(ReflectionUtils.java:164)
at org.apache.maven.surefire.booter.ProviderFactory$ProviderProxy.invoke(ProviderFactory.java:110)
at org.apache.maven.surefire.booter.SurefireStarter.invokeProvider(SurefireStarter.java:175)
at org.apache.maven.surefire.booter.SurefireStarter.runSuitesInProcessWhenForked(SurefireStarter.java:107)
at org.apache.maven.surefire.booter.ForkedBooter.main(ForkedBooter.java:68)
Caused by: org.hibernate.service.UnknownServiceException: Unknown service requested [org.hibernate.stat.spi.StatisticsImplementor]
at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:126)
at org.hibernate.internal.SessionFactoryImpl.getStatisticsImplementor(SessionFactoryImpl.java:1468)
at org.hibernate.internal.SessionFactoryImpl.getStatistics(SessionFactoryImpl.java:1464)
at org.hibernate.engine.transaction.internal.TransactionCoordinatorImpl.afterTransaction(TransactionCoordinatorImpl.java:140)
at org.hibernate.engine.transaction.internal.jdbc.JdbcTransaction.afterTransactionCompletion(JdbcTransaction.java:138)
at org.hibernate.engine.transaction.spi.AbstractTransactionImpl.rollback(AbstractTransactionImpl.java:214)
at org.springframework.orm.hibernate4.HibernateTransactionManager.doRollback(HibernateTransactionManager.java:488)
... 33 more
Please define the bean JukeBox in the test context if this is a service.
If this is dao then please inject the entitymanager, transaction manager and session factory to the bean.

org.springframework.beans.factory.BeanCreationException: as well as org.springframework.beans.BeanInstantiationException

I tried to do login and some database manipulations(insert,delete) in spring and also help with jsp.I am totally new to spring.I am getting the following error like bean creation exception.I have defined dvd as servlet name in web.xml. So my dvd_servlet.xml file is as like below
<beans.................>
<bean id="viewResolver" class="org.springframework.web.servlet.view.InternalResourceViewResolver">
<property name="viewClass" value="org.springframework.web.servlet.view.JstlView"/>
<property name="prefix" value="/"/>
<property name="suffix" value=".jsp"/>
</bean>
<bean id="dataSource" destroy-method="close" class="org.apache.commons.dbcp.BasicDataSource">
<property name="driverClassName" value="com.mysql.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3306/DVD"/>
<property name="username" value="root"/>
<property name="password" value="root"/>
</bean>
<bean name="DvdController" class="DvdController" >
<property name="dataSource" ref="dataSource"/>
</bean>
<bean name="LoginController" class="LoginController" >
<property name="dataSource" ref="dataSource"/>
</bean>
<bean name="AccountCreationController" class="AccountCreationController" >
<property name="dataSource" ref="dataSource"/>
</bean>
</beans>
my LoginController is like
public class LoginController implements Controller {
int check;
private DataSource dataSource;
public void setDataSource(DataSource dataSource) {
this.dataSource=dataSource;
}
public DataSource getDataSource() {
return dataSource;
}
JdbcTemplate jdbcTemplate=new JdbcTemplate(dataSource);
#RequestMapping(value="/Login",method=RequestMethod.POST)
public ModelAndView handleRequest(HttpServletRequest request, HttpServletResponse response) {
String userName = request.getParameter("userName");
String password=request.getParameter("password");
try {
String selectQuery=("SELECT * FROM USERDETAILS WHERE NAME='"+userName+"'AND PASSWORD='"+password+"'");
check=jdbcTemplate.update(selectQuery,new Object[]{});
System.out.println(check);
if(check!=0) {
response.sendRedirect("DvdController");
}
}
catch(IOException e) {
e.printStackTrace();
}
return new ModelAndView("failure");
}
My error is like as below:
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'LoginController' defined in ServletContext resource [/WEB-INF/dvd-servlet.xml]: Instantiation of bean failed; nested exception is org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [LoginController]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(support:AbstractAutowireCapableBeanFactory.java):965)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(support:AbstractAutowireCapableBeanFactory.java):911)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(support:AbstractAutowireCapableBeanFactory.java):485)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(support:AbstractAutowireCapableBeanFactory.java):456)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(support:AbstractBeanFactory.java):291)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(support:DefaultSingletonBeanRegistry.java):222)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(support:AbstractBeanFactory.java):288)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(support:AbstractBeanFactory.java):190)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(support:DefaultListableBeanFactory.java):580)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:442)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:458)
root cause
org.springframework.beans.BeanInstantiationException: Could not instantiate bean class [LoginController]: Constructor threw exception; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required
org.springframework.beans.BeanUtils.instantiateClass(beans:BeanUtils.java):141)
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(support:SimpleInstantiationStrategy.java):74)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(support:AbstractAutowireCapableBeanFactory.java):958)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(support:AbstractAutowireCapableBeanFactory.java):911)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(support:AbstractAutowireCapableBeanFactory.java):485)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(support:AbstractAutowireCapableBeanFactory.java):456)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(support:AbstractBeanFactory.java):291)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(support:DefaultSingletonBeanRegistry.java):222)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(support:AbstractBeanFactory.java):288)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(support:AbstractBeanFactory.java):190)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(support:DefaultListableBeanFactory.java):580)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:442)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:458)
root cause
java.lang.IllegalArgumentException: Property 'dataSource' is required
org.springframework.jdbc.support.JdbcAccessor.afterPropertiesSet(support:JdbcAccessor.java):134)
org.springframework.jdbc.core.JdbcTemplate.(core:JdbcTemplate.java):164)
LoginController.(LoginController.java:29)
sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:39)
sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:27)
java.lang.reflect.Constructor.newInstance(Constructor.java:513)
org.springframework.beans.BeanUtils.instantiateClass(beans:BeanUtils.java):126)
org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(support:SimpleInstantiationStrategy.java):74)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateBean(support:AbstractAutowireCapableBeanFactory.java):958)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(support:AbstractAutowireCapableBeanFactory.java):911)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(support:AbstractAutowireCapableBeanFactory.java):485)
org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(support:AbstractAutowireCapableBeanFactory.java):456)
org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(support:AbstractBeanFactory.java):291)
org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(support:DefaultSingletonBeanRegistry.java):222)
org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(support:AbstractBeanFactory.java):288)
org.springframework.beans.factory.support.AbstractBeanFactory.getBean(support:AbstractBeanFactory.java):190)
org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(support:DefaultListableBeanFactory.java):580)
org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:895)
org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:425)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:442)
org.springframework.web.servlet.FrameworkServlet.createWebApplicationContext(FrameworkServlet.java:458)
org.springframework.web.servlet.FrameworkServlet.initWebApplicationContext(FrameworkServlet.java:339)
please help me to clear this!!!
I see two issues here:
<bean name="LoginController" class="LoginController" >
<property name="dataSource" ref="dataSource"/>
</bean>
Is LoginController really the full qualified class name? It should be something like com.cy.LoginController
Second, Spring states that the constructor of the LoginController needs the property dataSource. It looks like the LoginController needs constructor injection of the dataSource, what you are doing is setter injection, so try this:
Instead of <property name="dataSource" ref="dataSource/>, write:
<constructor-arg ref="dataSource"/>

Resources