0

I'm new to SSH, and I'm using Spring 4, Hibernate 4 and Struts 2. When I create a unit testing for a DAO class, I got this exception.

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath*:testApplicationContext.xml"})
public class UserDaoTest {
    @Test
    public void testAddUserNotExists() {
        User user = new User("20116524", "785ee107c11dfe36de668b1ae7baacbb");
        userDao.addUser(user);

        assertNotNull(userDao.getUserByUsername("20116524"));
    }

    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    /**
     * UserDao object to test.
     */
    private UserDao userDao;
}

I tried to add following lines to web.xml, but it doesn't work.

Reference: Java / Hibernate - Write operations are not allowed in read-only mode

I believe there's something wrong with my applicationContext.xml, and here's the content:

<!-- Session Factory -->
<bean id="sessionFactory"
    class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
    <property name="dataSource" ref="dataSource" />
    <property name="configLocation" value="classpath:hibernate.cfg.xml"/>
    <property name="hibernateProperties">
        <props>
            <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
            <prop key="hibernate.show_sql">true</prop>
        </props>
    </property>
    <property name="packagesToScan">
        <list>
            <value>emis.accounts.model</value>
        </list>
    </property>
</bean>
<!-- Transaction -->
<tx:annotation-driven transaction-manager="transactionManager" />
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

There's no configuration about AOP and tx:advice. So I tried to add some lines:

<!-- Transaction -->
<bean id="transactionManager"
    class="org.springframework.orm.hibernate4.HibernateTransactionManager">
    <property name="sessionFactory" ref="sessionFactory" />
</bean>

<tx:advice id="txAdvice" transaction-manager="transactionManager">
    <tx:attributes>
        <tx:method name="*" propagation="REQUIRED" read-only="true"/>
        <tx:method name="get*" propagation="REQUIRED" read-only="true" />
        <tx:method name="find*" propagation="REQUIRED" read-only="true" />
        <tx:method name="list*" propagation="REQUIRED" read-only="true" />
        <tx:method name="load*" propagation="REQUIRED" read-only="true" />
        <tx:method name="save*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="add*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="save" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="update*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="update" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="delete*" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="delete" propagation="REQUIRED" rollback-for="Exception" />
        <tx:method name="*" propagation="REQUIRED" />
    </tx:attributes>
</tx:advice>

<aop:aspectj-autoproxy />
<aop:config>
    <aop:pointcut id="aopPointcut"
        expression="execution(* emis.*.service.*.*(..))" />
    <aop:advisor advice-ref="txAdvice" pointcut-ref="aopPointcut"/>
</aop:config>

However, I got another exception:

WARNING: Exception thrown from ApplicationListener handling ContextClosedEvent
java.lang.IllegalStateException: ApplicationEventMulticaster not initialized - call 'refresh' before multicasting events via the context: Root WebApplicationContext: startup date [Thu Mar 20 13:53:51 CST 2014]; root of context hierarchy
    at org.springframework.context.support.AbstractApplicationContext.getApplicationEventMulticaster(AbstractApplicationContext.java:346)
    at org.springframework.context.support.AbstractApplicationContext.publishEvent(AbstractApplicationContext.java:333)
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:880)
...

WARNING: Exception thrown from LifecycleProcessor on context close
java.lang.IllegalStateException: LifecycleProcessor not initialized - call 'refresh' before invoking lifecycle methods via the context: Root WebApplicationContext: startup date [Thu Mar 20 13:53:51 CST 2014]; root of context hierarchy
    at org.springframework.context.support.AbstractApplicationContext.getLifecycleProcessor(AbstractApplicationContext.java:359)
    at org.springframework.context.support.AbstractApplicationContext.doClose(AbstractApplicationContext.java:888)
    at org.springframework.context.support.AbstractApplicationContext.close(AbstractApplicationContext.java:841)
...

What should I do? Can anyone help me? Thanks a lot!!

Community
  • 1
  • 1
Haozhe Xie
  • 3,438
  • 7
  • 27
  • 53
  • How should adding stuff to your web.xml help your unit test which doesn't know anything about the fact that there is a web.xml. Can you post the full test case, the content of the `hibernate.cfg.xml` and the `UserDao`. – M. Deinum Mar 20 '14 at 07:08
  • There's nothing in the hibernate.cfg.xml. Only `` – Haozhe Xie Mar 20 '14 at 09:31

1 Answers1

0

First make up your mind on what you want to use for transactions. XML configuration or annotations @Transactional. Don't try to mix both of them.

If you use @Transactional make sure that your UserDao is annotated with the correct annotations.

If you use XML make sure that you have the ordering inside the tx:advice correct. Currently everything is read-only. The first match wins, as you have a wildcard * on top everything will match that pointcut. Next you don't need the <aop:aspectj-autoproxy /> as you have declared your aspect with an <aop:config /> block.

M. Deinum
  • 115,695
  • 22
  • 220
  • 224
  • You mean add @Transactional(readOnly = false) at the method? I did, but I got another exception: `Could not autowire method: public void emis.accounts.dao.UserDaoTest.setUserDao(emis.accounts.dao.UserDao); nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [emis.accounts.dao.UserDao] found for dependency: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {}` – Haozhe Xie Mar 20 '14 at 09:41
  • Then fix that problem. My guess is that UserDao is a concrete class which implements some interfaces. By default Spring uses JDK Dynamic proxies which are interface based. Add `proxy-target-class` to your `` to force class based proxies. – M. Deinum Mar 20 '14 at 10:04