Hi Doychi,

I've never used JPA before but have a little Hibernate experience. Now sure if you're using JPA through Hibernate or a different implementation?

Anyway the error you receive indicates that the session (EntityManager?) was closed (somewhere in the lower layer of your app) by the time the view needs to iterate over the roles.

My Spring/Hibernate is a little rusty but I think the following is happening. Your Repository contains the annotation @Transactional. Its a Spring construct which means (as I recall) that invoking any method on the Repository will create a new transaction before the method starts and commit the transaction before the method returns. Depending on how you configured your spring.xml, it might mean the session (EntityManager?) is closed when the transaction is committed.

How do you configure spring to create transactions and the EntityManager? Can you post it here?

You might want to look at the OpenEntityManagerInViewFilter which opens an EntityManager when the request arrives, and keeps it open until the request finishes. Thus the EntityManager will be open in your view and the lazy initialization won't occur. Alternatively you need to eagerly load the role.

Hope this helps.

bob


Doychi wrote:
Hi all,

I'm hoping someone can help me with a lazy initialisation error.  The error
I am getting is:

    failed to lazily initialize a collection of role ... no session or
session was closed

I am using Click 2's SpringClickServlet configured in the web.xml and JPA.

This is my web.xml, which seems to load everything okay.


<web-app>
        <listener>
        
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
        </listener>
        <servlet>
                <servlet-name>SpringClickServlet</servlet-name>
                
<servlet-class>au.org.pheno.f1.click.SpringClickServlet</servlet-class>
                <load-on-startup>0</load-on-startup>
        </servlet>
        <servlet-mapping>
                <servlet-name>SpringClickServlet</servlet-name>
                <url-pattern>*.htm</url-pattern>
        </servlet-mapping>
</web-app>


The page, which was taken from my login page, is trying to load a user
(principal) and display its roles to test the lazy loading issue.


/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package au.org.pheno.f1.test.pages;

import javax.annotation.Resource;

import org.apache.click.Page;
import org.apache.log4j.Logger;
import org.springframework.stereotype.Component;

import au.org.pheno.f1.domain.attendees.Principal;
import au.org.pheno.f1.repository.attendees.IPrincipalRepository;

/**
 * The login screen provides a user a way to login to the system.
* * @author doychi
 */
@Component("au.org.pheno.f1.test.pages.LoginPage")
public class LoginPage extends Page {

    private static final String TITLE = "Test Page";
    public String msg = "";
    private IPrincipalRepository repository;
    private Logger log = Logger.getLogger(LoginPage.class);
    public Principal principal;

    private Logger getLogger() {
        return log;
    }

    /**
     * Retrieve the title
* * @return the title
     */
    public String getTitle() {
        return TITLE;
    }

    /**
     * Set the principal repository to use for the page.
* * @param principalRepository
     *            the repository to use
     */
    @Resource(name = "principalRepository")
    public void setPrincipalRepository(IPrincipalRepository
principalRepository) {
        if (getLogger().isDebugEnabled()) {
            getLogger().debug("IPrincipalRepository set");
        }

        this.repository = principalRepository;
    }

    public IPrincipalRepository getPrincipalRepository() {
        return repository;
    }

    @Override
    public void onInit() {
        super.onInit();
        principal = repository.principalByLogin("admin");
        getLogger().info(principal.toString());
    }

}


The principal repository looks like this:


package au.org.pheno.f1.repository.attendees.jpa;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;

import org.apache.commons.lang.StringUtils;
import org.apache.commons.lang.builder.ReflectionToStringBuilder;
import org.apache.log4j.Logger;
import org.springframework.dao.DataAccessException;
import org.springframework.security.AuthenticationServiceException;
import org.springframework.security.BadCredentialsException;
import org.springframework.security.userdetails.UserDetails;
import org.springframework.security.userdetails.UsernameNotFoundException;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import au.org.pheno.f1.domain.attendees.Principal;
import au.org.pheno.f1.domain.attendees.Role;
import au.org.pheno.f1.repository.Repository;
import au.org.pheno.f1.repository.WrongNumberOfResultsReturnedException;
import au.org.pheno.f1.repository.attendees.IPrincipalRepository;

/**
 * Class description
* * * @version Enter version here..., 07/12/26
 * @author Enter your name here...
 */
@Component("principalRepository")
@Transactional(readOnly = true)
public class PrincipalRepository extends Repository<Principal> implements
        IPrincipalRepository {

    private String LOGIN_TAG = "usr";
    private static final Logger log = Logger
            .getLogger(PrincipalRepository.class);
    private static final String FILTER_OP_BOOLEAN = " = ";
    private static final String FILTER_OP_INTEGER = " = ";
    private static final String FILTER_OP_STRING = " LIKE ";
.
.
.
    /**
     * {...@inheritdoc}
     */
    @Override
    public Principal principalByLogin(String login) {
        Principal result;
        String query = "SELECT principal FROM PrincipalJpa principal WHERE "
                + "principal.username = :" + LOGIN_TAG;
        Map<String, Object> params = new TreeMap<String, Object>();

        params.put(LOGIN_TAG, login);

        result = (Principal) readOne(query, params);

        return result;
    }
.
.
.
}


The error appears to be thrown when my template tries to list the roles:


<html>
<body>
<p class="errorMessage">
    $!msg
</p>
${principal.firstName} ${principal.lastName}
#foreach( $role in $principal.roles)
        $role.name
#end
</body>
</html>


Does anyone have any thoughts on what I'm doing wrong?

Thanks,
--
Doychi

Reply via email to