Announcement Announcement Module
Collapse
No announcement yet.
LazyInitializationException in JPA-based UserDetailsService Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • LazyInitializationException in JPA-based UserDetailsService

    I'm setting up a UserDetailsService that retrieves the user's details via JPA, as recommended by Ben. My service looks like this (where Person and Skill are my own Roo-managed entities):

    Code:
    public class JpaUserDetailsService implements UserDetailsService {
    
        @Override
        public UserDetails loadUserByUsername(String username)
            throws UsernameNotFoundException
        {
            Person person = Person.find...; // find the person with this username (via JPA)
            Iterator<Skill> skills = person.getSkills().iterator(); // !!!
            ...
        }
    }
    The line marked "!!!" throws this error:

    Code:
    org.hibernate.LazyInitializationException: failed to lazily initialize a collection of role: lazy.Person.skills, no session or session was closed
            at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationException(AbstractPersistentCollection.java:358)
            at org.hibernate.collection.AbstractPersistentCollection.throwLazyInitializationExceptionIfNotConnected(AbstractPersistentCollection.java:350)
    
            at org.hibernate.collection.AbstractPersistentCollection.readSize(AbstractPersistentCollection.java:97)
            at org.hibernate.collection.PersistentSet.size(PersistentSet.java:139)
            at lazy.JpaUserDetailsService.loadUserByUsername(JpaUserDetailsService.java:22)
            at org.springframework.security.authentication.dao.DaoAuthenticationProvider.retrieveUser(DaoAuthenticationProvider.java:83)
            at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.authenticate(AbstractUserDetailsAuthenticationPro
    vider.java:125)
            at org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:121)
            at org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:49)
            at org.springframework.security.authentication.ProviderManager.doAuthentication(ProviderManager.java:139)
            at org.springframework.security.authentication.AbstractAuthenticationManager.authenticate(AbstractAuthenticationManager.java:49)
            at org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter.attemptAuthentication(UsernamePasswordAuthenticationFi
    lter.java:98)
            at org.springframework.security.web.authentication.AbstractAuthenticationProcessingFilter.doFilter(AbstractAuthenticationProcessingFilter.java
    :200)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:356)
            at org.springframework.security.web.authentication.logout.LogoutFilter.doFilter(LogoutFilter.java:106)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:356)
            at org.springframework.security.web.context.SecurityContextPersistenceFilter.doFilter(SecurityContextPersistenceFilter.java:80)
            at org.springframework.security.web.FilterChainProxy$VirtualFilterChain.doFilter(FilterChainProxy.java:356)
            at org.springframework.security.web.FilterChainProxy.doFilter(FilterChainProxy.java:150)
            at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:237)
            at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:167)
            at org.mortbay.jetty.servlet.ServletHandler$CachedChain.doFilter(ServletHandler.java:1084)
            at org.mortbay.jetty.servlet.ServletHandler.handle(ServletHandler.java:360)
            at org.mortbay.jetty.security.SecurityHandler.handle(SecurityHandler.java:216)
            at org.mortbay.jetty.servlet.SessionHandler.handle(SessionHandler.java:181)
            at org.mortbay.jetty.handler.ContextHandler.handle(ContextHandler.java:726)
            at org.mortbay.jetty.webapp.WebAppContext.handle(WebAppContext.java:405)
            at org.mortbay.jetty.handler.ContextHandlerCollection.handle(ContextHandlerCollection.java:206)
            at org.mortbay.jetty.handler.HandlerCollection.handle(HandlerCollection.java:114)
            at org.mortbay.jetty.handler.HandlerWrapper.handle(HandlerWrapper.java:152)
            at org.mortbay.jetty.Server.handle(Server.java:324)
            at org.mortbay.jetty.HttpConnection.handleRequest(HttpConnection.java:505)
            at org.mortbay.jetty.HttpConnection$RequestHandler.content(HttpConnection.java:843)
            at org.mortbay.jetty.HttpParser.parseNext(HttpParser.java:648)
            at org.mortbay.jetty.HttpParser.parseAvailable(HttpParser.java:211)
            at org.mortbay.jetty.HttpConnection.handle(HttpConnection.java:380)
            at org.mortbay.io.nio.SelectChannelEndPoint.run(SelectChannelEndPoint.java:395)
            at org.mortbay.thread.QueuedThreadPool$PoolThread.run(QueuedThreadPool.java:488)
    This surprised me, because Roo by default adds the following filter to web.xml:
    Code:
    <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>
    The LazyInitializationException is easily fixed by making my JpaUserDetailsService transactional (e.g. by adding the @Transactional annotation to it), but I'm unclear why that's necessary. Doesn't every thread already have an open Hibernate session (or EntityManager in JPA-speak) thanks to the OEMIV filter?
    Last edited by Andrew Swan; Feb 8th, 2010, 11:11 PM. Reason: Clarified that the Person lookup is done using JPA

  • #2
    Have you enabled debug logging to see when and why the session is closed before you hit this lazy loaded boundary? How is the service layer registered in your application (@Service, @Repository)?

    Comment


    • #3
      Another thing you could try is to change the sequence of the spring security filter and the open entity manager in view filter in web.xml. Try placing the security filter after the jpa filter.

      -Stefan

      Comment


      • #4
        I hit this problem today so swapped the filters round; this solves the problem. It seems that spring security calls the toString() method on the UserDetails instance and if you are using @RooToString then those lazy loaded associations are called in that method.

        Jon

        Comment


        • #5
          Swap these filters for new Roo apps?

          Thanks guys. I guess people have two ways to solve this now.

          Stefan, how about swapping the order of these filters by default for new Roo apps? A lot of people are going to want to use JPA in their UserDetailsService implementations in order to retrieve the logged-in user's roles, and are going to encounter this lazy-loading error (with the inevitable duplicate forum threads, etc.).

          Comment


          • #6
            Yes, we should change the sequence of filters so it all works well together. Please open a Jira ticket for this.

            Thanks,
            Stefan

            Comment


            • #7
              Logged.

              Logged as ROO-609.

              Comment


              • #8
                Thanks Andrew! I'll review if we should do this in 1.1 or earlier.

                -Stefan

                Comment


                • #9
                  Oh, I meant to write this reply in a different context. I'll certainly change this one for 1.0.2 release.

                  -Stefan

                  Comment


                  • #10
                    Hi, all - I created my project with Roo 1.1.1 last month and my web.xml was created with the improper ordering so it doesn't look like it's made it into a release yet. Thanks for the post though - easily enough solved.

                    Comment

                    Working...
                    X