0

I am getting the LazyInitializationException when i try to retrieve information inside a POJO.

User.java

public class User  implements java.io.Serializable {

 private Set groups = new HashSet(0);

    public Set getGroups() {
       return this.groups;
   }

}

UserController.java

@RequestMapping(value = "/home", method = RequestMethod.GET)
public ModelAndView getHome(HttpServletRequest request) throws Exception {
    ModelAndView mv;
    User user = SessionUtil.getSessionUser(request);
    if (user == null) {
        mv = new ModelAndView("redirect:/user/login");
    } else {
        mv = new ModelAndView("home");
        user = this.userService.getUserById(user.getId());

        // Exception here 
        Set<Group> groups = user.getGroups();
        mv.addObject("groups", groups);

        // This work fine
        List<Group> invitation_groups = this.userService.getInvitationGroups(user);
        mv.addObject("invitation_groups", invitation_groups);

        // This work fine
        List<Group> subscription_groups = this.userService.getSubscriptionGroups(user);
        mv.addObject("subscription_groups", subscription_groups);

    }

    return mv;
}

Database

=====
-User-
id
login

=====
-Goup-
id
user (Foreign key to user)


at org.hibernate.proxy.AbstractLazyInitializer.getImplementation(AbstractLazyInitializer.java:285)
at org.hibernate.proxy.pojo.javassist.JavassistLazyInitializer.invoke(JavassistLazyInitializer.java:185)
at model.pojo.User_$$_jvst464_2.getGroups(User_$$_jvst464_2.java)
at controller.UserController.getHome(UserController.java:151)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)

I think I understand why I get this exception : I always close the HibernateSession after all my transaction in my DAO so the session can't be open for the POJO request.

In an other hand user.getLogin() for exemple works. I think i dont understand well where the problem is. Is that because it uses a foreign key ?

I think i found a workaround here but I dont know how to implement it and if it's really efficient.

I know that if I remove session.close() from my DAO it will works but it's not the solution.

I hope someone can help me. Thanks.

Solution

  1. Remove all the hand made transactions
  2. Add transactionnal annotation
  3. User OpenSessionInView filter.

Thanks guys.

Charles Follet
  • 827
  • 1
  • 10
  • 28

2 Answers2

1

Why are you handling your session manually? Do you need that?

If not, you should use OpenSessionInView pattern. It will keep your session open until the request ends, but, be careful, you can run in trouble with lots of queries made to the database because the lazy load of collections. So whenever you can, try to fetch your data eagerly if you know that they will be used.

Your user.getLogin() returns a string right? Even if it was the one side of a relationship mapping, it would be fetched eagerly by default.

I'm not used with spring but I think spring has an OpenSessionInView filter to manage your session.

Marcus Henrique
  • 762
  • 1
  • 5
  • 15
  • Thank you Marcus. I dont need to handle it manually and yes getLogin() returns a string. So i remove all the manual Trasaction i have made and go into OpenSessionInView Filter approach? (I really don't know how to implement it) – Charles Follet Apr 26 '15 at 00:13
  • Yes, that's it. Very probably spring has an easy way to configure OpenSessionInView. – Marcus Henrique Apr 26 '15 at 00:14
  • In my DAO I have the classic Session session = HibernateUtil.getSessionFactory().openSession();. With the solution you suggested, i dont need to call session.close() at the end of each DAO function right? – Charles Follet Apr 26 '15 at 00:21
  • Yes, you don't even need to call openSession() manually because spring can inject the SessionFactory and you can call getCurrentSession() method. http://www.codejava.net/frameworks/spring/spring-4-and-hibernate-4-integration-tutorial-part-1-xml-configuration – Marcus Henrique Apr 26 '15 at 00:29
0

Its normal to handle transaction in API layer and using DTO, So you have: API -> Service -> DAO.

But since you only have transactional in DAO its probably okai, but then you have to take care of lazyload object in DAO., before transaction is closed.

// after this the transaction is open and closed, user object is hibernate jpa entity you usually get this.
user = this.userService.getUserById(user.getId());

The simplest solution is to loop through and do getId() in DAO, before returning user.

Set<Group> groups = user.getGroups();

 for (Group group in groups){
   group.getId(); 
}
user1648865
  • 99
  • 1
  • 5
  • Thank you. But i get the exception especially on the user.getGroups(); method .. so i can't reach the loop – Charles Follet Apr 26 '15 at 00:23
  • Where do you have @Transactional ?, you should have it in class level., and then do a getId in UserDao.getUserById(), before returning User. – user1648865 Apr 26 '15 at 00:28