Session persistence Open in JUnit / JPA / Hibernate / Struts and Spring integration tests - no session or session closed - LazyInitialization exception

My application uses Struts2 (mvc), Spring (Dependency Injection), JPA with Hibernate, JUnit along with struts2-junit plugins and struts2 Spring plugins.

Here is my test class:

@RunWith(SpringJUnit4ClassRunner.class)
public class CustomerSearchIntegrationTest extends StrutsSpringTestCase {

    @Test
    @Transactional
    public void testGetActionProxy() throws Exception {

        ActionProxy proxy;
        String result;

        ActionMapping mapping = getActionMapping("userInfo");
        assertNotNull(mapping);

        ..... // Some JUnit init code..

        ActionProxy proxy = getActionProxy("userInfo");
        UserInfo user = (UserInfo) proxy.getAction();
        result = proxy.execute();

        assertEquals("details", result);
        System.out.prinltn("Username:" + user.getFirstName());

    }
}

      

GetUserInfo

public class UserInfo extends ActionSupport {
     User user; // Entity
     UDetails details; // Entity

     public String getUserDetails() { //Action method
       user = userMgmt.getUser(usrId);
       if (user != null ) {
            for(UDetails det : user.getUDetails()) { // user.getUDetails() there is where exception gets thrown.
                if(det.getStreet().equals(street)){
                    details = det;
                    break;
                }
            }
       }
       ...
       ...
    }
}

      

User and UDetails are objects. UDetalis ManyToMany

s User

and is lazily extracted. All objects are annotated.

UserMgmt

public class UserMgmt {
    public User getUser(String userId) {
        return userDao.getUser(userId);
    }
}

      

UserDAO

public class UserDAO extends AbstractJPAImpl{

    public User getUser(String userId) {
        User user = (User) getSession().get(User.class, userId);
        return user;
    }
}

      

AbstractJPAImpl

@Transactional
public abstract class AbstractJPAImpl {

    private EntityManager em;

    @PersistenceContext
    protected void setEntityManager(EntityManager em) {
        this.em = em;
    }

    @Transactional
    protected Session getSession() {
        return (Session) em.getDelegate();
    }

    ....
}

      

jpaContext.xml

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor"/>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean">
  // other config stuff
</bean>

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager">
    <property name="entityManagerFactory" ref="entityManagerFactory"/>
</bean>

<tx:annotation-driven transaction-manager="transactionManager"/>

      

All config / context files are loaded in order. The Struts.xml, jpacontext.xml, beans.xml, etc. files are loaded.

But I am getting an exception:

failed to lazily initialize a collection of role: com.my.data.User.udetails, no session or session was closed

org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: 

      

on the next line:

 for(UDetails det : user.getUDetails())

      

Obviously its trying to load is UDetails

lazy, then the exception is being thrown. However, this application works fine when deployed to AppServer (WebSphere).

What could I be doing wrong? How do I open a session session?

Update: More

I am using OpenEntityManagerInViewFilter

. My web.xml is below

<filter>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <filter-class>
        org.springframework.orm.jpa.support.OpenEntityManagerInViewFilter</filter-class>
</filter>

<filter-mapping>
    <filter-name>OpenEntityManagerInViewFilter</filter-name>
    <url-pattern>/*</url-pattern>
</filter-mapping>

      

Update:

This finally works by passing a parameter to the @PersistenceContext

annotation like below:

@PersistenceContext(type=PersistenceContextType.EXTENDED)

      

So I guess the transaction is being closed, but the entities are running outside of the transaction because of the EXTENDED type. However, I cannot change the code as above and leave it forever. So I need to remove it.

So, I guess I have these options, but not sure if it is doable and how:

  • Get persistence context from Spring application context and pass parameter. Not sure if this is relevant or possible.

  • Get the session / entity manager from the application context and add another transaction level. Thus, the session is performed in two transactions. One of them runs from my test code and the other runs into existing code, which automatically closes, while mine stays open until my test code finishes executing.

For the second, I tried annotating the method with @Transactional

. But it didn't work. I do not know why.

Any help?

Update

It looks like the struts-junit plugin is NOT loading / reading the web.xml it has OpenEntityManagerInViewFilter

. So it didn't boot.

Any other work around or tweak this filter?

+4


source to share


1 answer


If it helps anyone, I haven't been able to get @Transaction to work. But I put this:

 @PersistenceContext(type=PersistenceContextType.EXTENDED)

      



and now it works!

.....

+2


source







All Articles