Spring Beans not Initialized Completely - spring

I am facing a strange problem with Spring, a bean is not initialized completely with injected dependency. It works fine if a thread sleep of minimal 5 seconds is introduced before accessing that bean.
This is not a case of notify/wait as this is in control of Spring.
Another pointer is that the bean's methods are static and variable is also static.
Any hints will be appreciated.
Here's the code
public final class UserPreferencesUtils {
/** siamHandlerFacade variable. */
private static SiamHandlerFacade siamHandlerFacade;
=====
public static String getSubscriberXXXX() {
try {
// Here the above is being used
// This method is also static
showSubscriberProfile = siamHandlerFacade
.retrieveSubscriberProfile(retrieveSubscriberProfile);
} catch (WebServiceClientException ex) {
ex.getMessage();
bean configuration
<bean id="userPreferenceUtils" class="aero.sita.voyager.ias.client.commons.utils.UserPreferencesUtils">
<property name="siamHandlerFacade" ref="siamServiceManagerRemoteService"></property>
<property name="queryLMData" ref="queryLMData"></property>
</bean>
<bean id="siamServiceManagerRemoteService"
class="aero.sita.voyager.ias.client.commons.webserviceproxy.SiamHandlerFacadeImpl">
<property name="siamWebServiceCallProxy" ref="siamWebServiceCallProxy"/>
<property name="officeWebServiceCallProxy" ref="officeWebServiceCallProxy"/>
<property name="subscriberWebServiceCallProxy" ref="subscriberWebServiceCallProxy"/>
<property name="masterAgreementWebServiceCallProxy" ref="masterAgreementWebServiceCallProxy"/>
<property name="agreementWebServiceCallProxy" ref="agreementWebServiceCallProxy"/>
<property name="userProfileWebServiceCallProxy" ref="userProfileWebServiceCallProxy"/>
</bean>

Related

Hibernate Transaction Manager not committing data changes

I'm using Hibernate 4 to write data to an H2 embedded in-memory database and there seems to be a problem with transactions. The application already uses Oracle and H2 has been added with a separate DataSource, SessionFactory, and TransactionManager. The original TransactionManager is marked as default and the H2 TransactionManager has the qualifier memTransactions
The following code - specifically the load function - correctly populates the memEvents variable at the end with the written data.
#Repository
#Transactional(transactionManager = "memTransactions")
public class EventMemDaoHibernate implements EventMemDao {
#Autowired
#Qualifier(value = "memSessionFactory")
private SessionFactory memSessionFactory;
#Override
public List<EventMem> getEvents() {
return memSessionFactory.getCurrentSession().createCriteria(EventMem.class).list();
}
#Override
public void load(List<Event> allEvents) {
Session session = memSessionFactory.getCurrentSession();
for (Event e : allEvents) {
EventMem memEvent = new EventMem(e);
session.save(memEvent);
}
List<EventMem> memEvents = getEvents(); // correct
}
}
However the following code produces an empty memEvents list
#Autowired
private EventMemDao eventMemDao;
List<Event> allEvents = eventDao.getAllEvents();
eventMemDao.load(allEvents); // calls the load function shown above
List<EventMem> memEvents = eventMemDao.getEvents(); // empty
I assume this is related to transaction management (e.g.: data is not auto-committed after the call to .save()). However when I tried explicitly beginning and committing a transaction within EventMemDaoHibernate#load, I receive this error:
nested transactions not supported
So, from what I can tell the TransactionManager is working.
My TransactionManager and related bean definitions are shown below.
<bean
id="memTransactionManager"
class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="memSessionFactory" />
<qualifier value="memTransactions"/>
</bean>
<bean id="hDataSource" class="org.h2.jdbcx.JdbcDataSource">
<property name="url" value="jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;INIT=RUNSCRIPT FROM 'classpath:scripts/init-h2.sql'" />
<property name="user" value="sa" />
<property name="password" value="" />
</bean>
<bean
id="memSessionFactory"
class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
<property name="dataSource" ref="hDataSource" />
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
</props>
</property>
</bean>
This was due to my configuration error (of course). I didn't fully grasp that the connection URL was evaluated every time a session was opened against H2 and that means init-h2.sql was executed repeatedly. init-h2.sql included a truncate followed by an insert so it was dropping and recreating data every time Hibernate opened a session.

Circular dependency (with inner bean) without duplication - is is possible?

Take the following configuration:
<beans>
<bean name="myToyota" class="Car">
<property name="contents">
<list>
<bean class="Wheel">
<property name="designation"><value>front-left</value></property>
<property name="parent"><ref bean="myToyota"/></property>
</bean>
<bean class="Wheel">
<property name="designation"><value>front-right</value></property>
<property name="parent"><ref bean="myToyota"/></property>
</bean>
</list>
</property>
</bean>
</beans>
Is it possible to build this graph without directly referencing myToyota from the Wheel beans? (Maybe using SpEL).
My concern is that I can not copy-paste the description of the Wheels to an other Car bean without introducing the possibility of broken references (that's me forgetting to adjust the parent property by hand).
In other words: is there a way an inner bean can referece it's containing bean without knowing its name?
What if you do something like the following:
public class Car {
private List contents;
public List getContents() {
return contents;
}
public void setContents(List contents) {
this.contents = contents;
for (Iterator iterator = contents.iterator(); iterator.hasNext();) {
Wheel object = (Wheel) iterator.next();
object.setParent(this);
}
}
}

Spring 3 MVC:java.lang.IllegalArgumentException: Property 'dataSource' is required.How to set JdbcTemplate correctly?

I'm new to Spring development.And right now,i'm really facing a problem.Here are the code snippets to make you realize my problem clearly.............
Here is my DAO class:
public class LoginDaoImpl {
private DataSource dataSource;
private JdbcTemplate jdbcTemplate;
public void setDataSource(DataSource dataSource) {
this.dataSource = dataSource;
}
public int checkLoginDetails(LoginVo loginVo){
String sql = "select count(*) from empsctygrp where username=? and password=?";
jdbcTemplate = new JdbcTemplate(dataSource);
int count = jdbcTemplate.queryForObject(sql,new Object[]{loginVo.getUserName(),loginVo.getPassword()},Integer.class);
return count;
}
}
Now here is my Business-Object(BO) class:
public class LoginBo {
LoginDaoImpl loginDaoImpl = new LoginDaoImpl();
public int checkLoginDetails(LoginVo loginVo){
return loginDaoImpl.checkLoginDetails(loginVo);
}
}
Now,here is my dispatcher-servlet xml code:
<bean id="dataSource"
class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="oracle.jdbc.driver.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:#117.194.83.9:1521:XE"/>
<property name="username" value="system"/>
<property name="password" value="password1$"/>
</bean>
<bean id="loginDaoImpl" class="com.abhinabyte.dao.LoginDaoImpl">
<property name="dataSource" ref="dataSource" />
</bean>
Now whenever i'm trying to run this on server the following exception is given:
SEVERE: Servlet.service() for servlet [dispatcher] in context with path [/A] threw exception [Request processing failed; nested exception is java.lang.IllegalArgumentException: Property 'dataSource' is required] with root cause
java.lang.IllegalArgumentException: Property 'dataSource' is required
Please help me solve this problem.............:(
Try this in LoginBo class:
#Autowired
LoginDaoImpl loginDaoImpl;
instead of
LoginDaoImpl loginDaoImpl = new LoginDaoImpl();
The problem is that you manually instantiate LoginDaoImpl.
I was having the same problem and could not find a comprehensive answer on the web, so I decided to post one here for anyone else, or for future me.
I'm still learning so if you think I have made a mistake below, please feel free to edit.
Summary:
Include <integration:annotation-config/> <context:component-scan base-package="myproject"/> in your servlet to pick up annotations
Configure JUnit tests with #RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration("file:WEB-INF/FinanceImportTool-servlet.xml")
Don't autowire dataSource or jdbcTemplate if these fields are already provided by a parent class e.g. StoredProcedure
Don't use new() as this initializes classes outside the applicationContext
Beware of using properties in your constructor which have not yet been set - obvious but embarrassingly easy to do
My original class (now altered):
public class MyDAOImpl extends StoredProcedure implements MyDAO {
private static final String SPROC_NAME = "dbo.MySP";
public MyDAOImpl(DataSource dataSource) {
super(dataSource, SPROC_NAME);
// ...declared parameters...
compile();
}
}
MyProject-servlet.xml file (only relevant bits included):
<!-- Used by Spring to pick up annotations -->
<integration:annotation-config/>
<context:component-scan base-package="myproject"/>
<bean id="MyDAOBean" class="myproject.dao.MyDAOImpl" >
<constructor-arg name="dataSource" ref="myDataSource"/>
</bean>
<!-- properties stored in a separate file -->
<bean id="myDataSource" class="com.microsoft.sqlserver.jdbc.SQLServerDataSource">
<property name="databaseName" value="${myDataSource.dbname}" />
<property name="serverName" value="${myDataSource.svrname}" />
<!-- also loaded portNumber, user, password, selectMethod -->
</bean>
Error: property 'dataSource' is required, or NullPointerException (1)
Other answers say make sure you have passed dataSource as a <property> for your bean in the servlet, etc.
I think #Abhinabyte the OP needed to annotate his setDataSource() method with #Annotation, and use <integration:annotation-config/> <context:component-scan base-package="myproject"/> in his servlet to successfully pass in dataSource as a dependency to LoginDaoImpl.
In my case, I tried adding 'dataSource' as a property and autowiring it. The "dataSource is required" error message became a NullPointerException error.
I realised after far too long that MyDAOImpl extends StoredProcedure.
dataSource was already a property of StoredProcedure. By having a dataSource property for MyDAOImpl, the autowiring was not picking up and setting the dataSource property of StoredProcedure, which left dataSource for StoredProcedure as null.
This was not picked up when I tested the value of MyDAOImpl.dataSource, as of course by now I had added a MyDAOImpl.dataSource field that had been autowired successfully. However the compile() method inherited from StoredProcedure used StoredProcedure.dataSource.
Therefore I didn't need public DataSource dataSource; property in MyDAOImpl class. I just needed to use the StoredProcedure constructor with super(dataSource, sql); in the constructor for MyDAOImpl.
I also didn't need a MyDAOImpl.jdbcTemplate property. It was set automatically by using the StoredProcedure(dataSource, sql) constructor.
Error: NullPointerException (2)
I had been using this constructor:
private static final String SPROC_NAME = "dbo.MySP";
public MyDAOImpl(DataSource dataSource) {
super(dataSource, SPROC_NAME);
}
This caused a NullPointerException because SPROC_NAME had not been initialized before it was used in the constructor (yes I know, rookie error). To solve this, I passed in sql as a constructor-arg in the servlet.
Error: [same error message appeared when I had changed file name]
The applicationContext was referring to the bin/ instances of my beans and classes. I had to delete bin/ and rebuild the project.
My new class:
public class MyDAOImpl extends StoredProcedure implements MyDAO {
#Autowired // Necessary to prevent error 'no default constructor found'
public MyDAOImpl(DataSource dataSource, String sql) {
super(dataSource, sql);
// ...declared parameters...
compile();
}
New MyProject-servlet.xml file (only relevant bits included):
<!-- Used by Spring to pick up annotations -->
<integration:annotation-config/>
<context:component-scan base-package="myproject"/>
<bean id="myDAOBean" class="org.gosh.financeimport.dao.MyDAOImpl" >
<constructor-arg name="dataSource" ref="reDataSource"/>
<constructor-arg name="sql" value="dbo.MySP" />
</bean>
<!-- properties stored in a separate file -->
<bean id="myDataSource" class="com.microsoft.sqlserver.jdbc.SQLServerDataSource">
<property name="databaseName" value="${myDataSource.dbname}" />
<property name="serverName" value="${myDataSource.svrname}" />
<!-- also loaded portNumber, user, password, selectMethod -->
</bean>
Helpful places:
If you can get past the rage, this answer on Spring forums might help too
This answer gives a broad introduction to Spring configuration
This answer has simple but useful suggestions
You should annotate that beans that will suffer IoC. Like
#Bean public class LoginDAOImpl { #Inject DataSource dataSource;......}
You set up in spring context this beans, but, you're not using them.
OBS:
When I use the JDBCTemplate I configure de IoC of JDBC like
<bean id="dataSourcePerfil" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
<property name="driverClassName" value="${br.com.dao.jdbc.driver}" />
<property name="url" value="${br.com.dao.jdbc.url}" />
<property name="username" value="${br.com.dao.jdbc.user}" />
<property name="password" value="${br.com.dao.jdbc.pass}" />
</bean>
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg ref="dataSourcePerfil" />
</bean>
then.... after at all
#Bean
public class LoginDAOImpl {
#Autowired
private JdbcTemplate jdbcTemplate;
#Override
public List<ClienteReport> getClientes() {
return Collections<ClienteReport>. emptyList();
}
}

transactions not working with Spring 3.1 – H2 – junit 4– hibernate 3.2

I have the following test..
#RunWith(SpringJUnit4ClassRunner.class)
#ContextConfiguration(locations = {"/schedule-agents-config-context.xml"})
#TransactionConfiguration(transactionManager = "transactionManager", defaultRollback = true)
#Transactional
public class H2TransactionNotWorkingTest extends SubmitAgentIntegratedTestBase {
private static final int FIVE_SUBMISSIONS = 5;
#Autowired
private ApplicationSubmissionInfoDao submissionDao;
private FakeApplicationSubmissionInfoRepository fakeRepo;
#Before
public void setUp() {
fakeRepo = fakeRepoThatNeverFails(submissionDao, null);
submitApplication(FIVE_SUBMISSIONS, fakeRepo);
}
#Test
#Rollback(true)
public void shouldSaveSubmissionInfoWhenFailureInDatabase() {
assertThat(fakeRepo.retrieveAll(), hasSize(FIVE_SUBMISSIONS));
}
#Test
#Rollback(true)
public void shouldSaveSubmissionInfoWhenFailureInXmlService() {
assertThat(fakeRepo.retrieveAll().size(), equalTo(FIVE_SUBMISSIONS));
}
}
...and the following config...
<jdbc:embedded-database id="dataSource" type="H2">
<jdbc:script location="classpath:/db/h2-schema.sql" />
</jdbc:embedded-database>
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
<bean id="transactionalSessionFactory"
class="org.springframework.orm.hibernate3.annotation.AnnotationSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="hibernateProperties">
<props>
<prop key="hibernate.dialect">org.hibernate.dialect.H2Dialect</prop>
<prop key="hibernate.show_sql">false</prop>
<prop key="hibernate.cache.use_second_level_cache">false</prop>
<prop key="hibernate.cache.use_query_cache">false</prop>
</props>
</property>
<property name="namingStrategy">
<bean class="org.hibernate.cfg.ImprovedNamingStrategy"/>
</property>
<property name="configurationClass" value="org.hibernate.cfg.AnnotationConfiguration"/>
<property name="packagesToScan" value="au.com.mycomp.life.snapp"/>
</bean>
<bean id="regionDependentProperties" class="org.springframework.core.io.ClassPathResource">
<constructor-arg value="region-dependent-service-test.properties"/>
</bean
>
I have also set auto commit to false in the sql script
SET AUTOCOMMIT FALSE;
There are not REQUIRES_NEW in the code.
Why is the rollback not working in the test?
Cheers
Prabin
I have faced the same problem but I have finally solved it albeit I don't use Hibernate (shouldn't really matter).
The key item making it work was to extend the proper Spring unit test class, i.e. AbstractTransactionalJUnit4SpringContextTests. Note the "Transactional" in the class name. Thus the skeleton of a working transactional unit test class looks like:
#ContextConfiguration(locations = {"classpath:/com/.../testContext.xml"})
public class Test extends AbstractTransactionalJUnit4SpringContextTests {
#Test
#Transactional
public void test() {
}
}
The associated XML context file has the following items contained:
<jdbc:embedded-database id="dataSource" type="H2" />
<tx:annotation-driven transaction-manager="transactionManager"/>
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
Using this setup the modifications by each test method is properly rolled back.
Regards, Ola
I'm experiencing similar problems, I'm also using TestNG + Spring test support and Hibernate. What happens is that Hibernate disables autocommit on the connection before the transaction begins and it remembers the original autocommit setting:
org.hibernate.engine.transaction.internal.jdbc#JdbcTransaction:
#Override
protected void doBegin() {
try {
if ( managedConnection != null ) {
throw new TransactionException( "Already have an associated managed connection" );
}
managedConnection = transactionCoordinator().getJdbcCoordinator().getLogicalConnection().getConnection();
wasInitiallyAutoCommit = managedConnection.getAutoCommit();
LOG.debugv( "initial autocommit status: {0}", wasInitiallyAutoCommit );
if ( wasInitiallyAutoCommit ) {
LOG.debug( "disabling autocommit" );
managedConnection.setAutoCommit( false );
}
}
catch( SQLException e ) {
throw new TransactionException( "JDBC begin transaction failed: ", e );
}
isDriver = transactionCoordinator().takeOwnership();
}
Later on, after rolling back the transaction, it will release the connection. Doing so hibernate will also restore the original autocommit setting on the connection (so that others who might be handed out the same connection start with the original setting). However, setting the autocommit during a transaction triggers an explicit commit, see JavaDoc
In the code below you can see this happening. The rollback is issued and finally the connection is released in releaseManagedConnection. Here the autocommit will be re-set which triggers a commit:
org.hibernate.engine.transaction.internal.jdbc#JdbcTransaction:
#Override
protected void doRollback() throws TransactionException {
try {
managedConnection.rollback();
LOG.debug( "rolled JDBC Connection" );
}
catch( SQLException e ) {
throw new TransactionException( "unable to rollback against JDBC connection", e );
}
finally {
releaseManagedConnection();
}
}
private void releaseManagedConnection() {
try {
if ( wasInitiallyAutoCommit ) {
LOG.debug( "re-enabling autocommit" );
managedConnection.setAutoCommit( true );
}
managedConnection = null;
}
catch ( Exception e ) {
LOG.debug( "Could not toggle autocommit", e );
}
}
This should not be a problem normally, because afaik the transaction should have ended after the rollback. But even more, if I issue a commit after a rollback it should not be committing any changes if there were no changes between the rollback and the commit, from the javadoc on commit:
Makes all changes made since the previous commit/rollback permanent
and releases any database locks currently held by this Connection
object. This method should be used only when auto-commit mode has been
disabled.
In this case there were no changes between rollback and commit, since the commit (triggered indirectly by re-setting autocommit) happens only a few statements later.
A work around seems to be to disable autocommit. This will avoid restoring autocommit (since it was not enabled in the first place) and thus prevent the commit from happening. You can do this by manipulating the id for the embedded datasource bean. The id is not only used for the identification of the datasource, but also for the databasename:
<jdbc:embedded-database id="dataSource;AUTOCOMMIT=OFF" type="H2"/>
This will create a database with name "dataSource". The extra parameter will be interpreted by H2. Spring will also create a bean with name "dataSource;AUTOCOMMIT=OFF"". If you depend on the bean names for injection, you can create an alias to make it cleaner:
<alias name="dataSource;AUTOCOMMIT=OFF" alias="dataSource"/>
(there isn't a cleaner way to manipulate the embedded-database namespace config, I wish Spring team would have made this a bit better configurable)
Note: disabling the autocommit via the script (<jdbc:script location="...") might not work, since there is no guarantee that the same connection will be re-used for your test.
Note: this is not a real fix but merely a workaround. There is still something wrong that cause the data to be committed after a rollback occured.
----EDIT----
After searching I found out the real problem. If you are using HibernateTransactionManager (as I was doing) and you use your database via the SessionFactory (Hibernate) and directly via the DataSource (plain JDBC), you should pass both the SessionFactory and the DataSource to the HibernateTransactionManager. From the Javadoc:
Note: To be able to register a DataSource's Connection for plain JDBC code, this instance >needs to be aware of the DataSource (setDataSource(javax.sql.DataSource)). The given >DataSource should obviously match the one used by the given SessionFactory.
So eventually I did this:
<bean id="transactionManager" class="org.springframework.orm.hibernate4.HibernateTransactionManager">
<property name="sessionFactory" ref="sessionFactory" />
<property name="dataSource" ref="dataSource" />
</bean>
And everything worked for me.
Note: the same goes for JpaTransactionManager! If you both use the EntityManager and perform raw JDBC access using the DataSource, you should supply the DataSource separately next to he EMF. Also don't forget to use DataSourecUtils to obtain a connection (or JDBCTemplate which uses DataSourceUtils internally to obtain the connection)
----EDIT----
Aight, while the above did solve my problem, it is not the real cause after all :)
In normal cases when using Spring's LocalSessionFactoryBean, setting the datasource will have no effect since it's done for you.
If the SessionFactory was configured with LocalDataSourceConnectionProvider, i.e. by Spring's LocalSessionFactoryBean with a specified "dataSource", the DataSource will be auto-detected: You can still explicitly specify the DataSource, but you don't need to in this case.
In my case the problem was that we created a caching factory bean that extended LocalSessionFactoryBean. We only use this during testing to avoid booting the SessionFactory multiple times. As told before, Spring test support does boot multiple application contexts if the resource key is different. This caching mechanism mitigates the overhead completely and ensures only 1 SF is loaded.
This means that the same SessionFactory is returned for different booted application contexts. Also, the datasource passed to the SF will be the datasource from the first context that booted the SF. This is all fine, but the DataSource itself is a new "object" for each new application context. This creates a discrepancy:
The transaction is started by the HibernateTransactionManager. The datasource used for transaction synchronization is obtained from the SessionFactory (so again: the cached SessionFactory with the DataSource instance from the application context the SessionFactory was initially loaded from). When using the DataSource in your test (or production code) directly, you'll be using the instance belonging to the app context active at that point. This instance does not match the instance used for the transaction synchronization (extracted from the SF). This result into problems as the connection obtained will not be properly participating in the transaction.
By explicitly setting the datasource on the transactionmanager this appeared to be solved since the post initialization will not obtain the datasource from the SF but use the injected one instead. The appropriate way for me was to adjust the caching mechanism and replace the datasource in the cached SF with the one from the current appcontext each time the SF was returned from cache.
Conclusion: you can ignore my post:) as long as you're using HibernateTransactionManager or JtaTransactionManager in combination with some kind of Spring support factory bean for the SF or EM you should be fine, even when mixing vanilla JDBC with Hibernate. In the latter case don't forget to obtain connections via DataSourceUtils (or use JDBCTemplate).
Try this:
remove the org.springframework.jdbc.datasource.DataSourceTransactionManager
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
and replace it with the org.springframework.orm.jpa.JpaTransactionManager
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="dataSource" ref="dataSource"/>
</bean>
or you inject an EntityManagerFactory instead ...
<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
<property name="entityManagerFactory" ref="entityManagerFactory" />
</bean>
you need an EntityManagerFactory then, like the following
<bean id="entityManagerFactory"
class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="jpaVendorAdapter">
<bean id="jpaAdapter"
class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter">
<property name="showSql" value="true" />
<property name="generateDdl" value="true" />
</bean>
</property>
</bean>
You haven't shown all the pieces to the puzzle. My guess at this point would be that your ApplicationSubmissionInfoDao is transactional and is committing on its own, though I'd think that would conflict with the test transactions if everything were configured properly. To get more of an answer, ask a more complete question. The best thing would be to post an SSCCE.
Thanks Ryan
The test code is something like this.
#Test
#Rollback(true)
public void shouldHave5ApplicationSubmissionInfo() {
for (int i = 0; i < 5; i++) {
hibernateTemplate.saveOrUpdate(new ApplicationSubmissionInfoBuilder()
.with(NOT_PROCESSED)
.build());
}
assertThat(repo.retrieveAll(), hasSize(5));
}
#Test
#Rollback(true)
public void shouldHave5ApplicationSubmissionInfoAgainButHas10() {
for (int i = 0; i < 5; i++) {
hibernateTemplate.saveOrUpdate(new ApplicationSubmissionInfoBuilder()
.with(NOT_PROCESSED)
.build());
}
assertThat(repo.retrieveAll(), hasSize(5));
}
I figure out that embedded DB define using jdbc:embedded-database don't have transaction support. When I used commons DBCP to define the datasource and set default auto commit to false, it worked.
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" scope="singleton">
<property name="driverClassName" value="org.h2.Driver" />
<property name="url" value="jdbc:h2:~/snappDb"/>
<property name="username" value="sa"/>
<property name="password" value=""/>
<property name="defaultAutoCommit" value="false" />
<property name="connectionInitSqls" value=""/>
</bean>
None of the above worked for me!
However, the stack i am using is [spring-test 4.2.6.RELEASE, spring-core 4.2.6.RELEASE, spring-data 1.10.1.RELEASE]
The thing is, using any unit test class annotated with [SpringJUnit4ClassRunner.class] will result in an auto-rollback functionality by spring library design
check ***org.springframework.test.context.transaction.TransactionalTestExecutionListener*** >> ***isDefaultRollback***
To overcome this behavior just annotate the unit test class with
#Rollback(value = false)

Ant task for Spring Validation

I need an ANT task to validate spring configuration. I need to find problems at build time before runtime ? For example, In spring context file contains a property a bean, but this bean doesnt have this property.
In eclipse, there is a tool Spring Explorer that do this validation.
thanks,
org.springframework.web.context.ContextLoaderListener failed: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'readController' defined in class path resource [applicationContext.xml]: Error setting property values; nested exception is org.springframework.beans.NotWritablePropertyException: Invalid property 'productOperations' of bean class [com.bee.view.json.ReadController]: Bean property 'productOperations' is not writable or has an invalid setter method.
Does the parameter type of the setter match the return type of the getter?.
An easy way to ensure that your context is valid would be to create a JUnit test, which loads the context. Using the spring-test.jar support classes makes that easy:
public class MyTest extends AbstractDependencyInjectionSpringContextTests {
// this will be injected by Spring
private QueryDao queryDao;
private MyBusinessObject myBusinessObject;
// ensure that spring will inject the objects to test by name
public MyTest () {
setAutowireMode(AUTOWIRE_BY_NAME);
}
#Override
protected String[] getConfigLocations() {
return new String[] { "applicationContextJUnit.xml" };
}
public void testQueryDao() {
List<SomeData> list = queryDao.findSomeData();
assertNotNull(list);
// etc
}
public void testMyBusinessObject() {
myBusinessObject.someMethod();
}
public void setQueryDao(QueryDao queryDao) {
this.queryDao = queryDao;
}
}
The problem with loading a context that is used in a web application is that JUnit does not necessarily have access to the same resources (e.g. JNDI data sources), so if you've got the following in your "applicationContext.xml":
<beans ...>
<bean id="myBusinessObject" class="com.test.MyBusinessObject">
<property name="queryDao" ref="queryDao"/>
</bean>
<bean id="queryDao" class="com.test.QueryDao">
<property name="dataSource" ref="dataSource"/>
</bean>
<jee:jndi-lookup
id="dataSource"
jndi-name="jdbc/mydatasource"
resource-ref="true"
cache="true"
lookup-on-startup="false"
proxy-interface="javax.sql.DataSource"/>
</beans>
and your "applicationContextJUnit.xml" would import your "real" application context and redefine resources:
<beans ...>
<import resource="classpath:applicationContext.xml"/>
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
<property name="driverClassName" value="oracle.jdbc.OracleDriver"/>
<property name="url" value="jdbc:oracle:thin:..."/>
<property name="username" value="scott"/>
<property name="password" value="tiger"/>
</bean>
</beans>
That way your unit tests will load the application context (even the ones that you don't explicitly test in your unit test), and you can have the confidence that your context is correct, because Spring itself loaded it. If you have an error, then the unit tests will fail.

Resources