3

I have run into LazyInitializationException and then I ran into the following paragraph from the official doc. Unfortunately, it makes absolutely no sense to me. Please help.

(The code block above the paragraph in the doc.)

@GET
@Timed
@UnitOfWork
public Person findPerson(@PathParam("id") LongParam id) {
    return dao.findById(id.get());
}

Important

The Hibernate session is closed before your resource method’s return value (e.g., the Person from the database), which means your resource method (or DAO) is responsible for initializing all lazily-loaded collections, etc., before returning. Otherwise, you’ll get a LazyInitializationException thrown in your template (or null values produced by Jackson).

First The Hibernate session is closed before your resource method’s return value. How is this possible? This would have been possible had there been a try-finally block around my resource's return statement, but that is not the case here.

My resource should have been invoked by another method, which I am guessing would open the Hibernate session before my resource method is invoked and would then close the session after my resource method returns. How can it close it before my method returns. I don't get it.

The most important part - which means your resource method (or DAO) is responsible for initializing all lazily-loaded collections, etc., before returning. I have no Hibernate experience. I am using it for the first time now. How do I initialize, or rather what is exactly is meant by "initialize" in context of Hibernate? A code example will help a lot.

PS: This question might look odd, and someone at a cursory glance might even suggest to move it to "English Language and Usage", but please read it carefully. This is a technical question, not paragraph dissection.

Edit: Added the code block from the doc else it won't make sense anyone. Also I removed one paragraph from my question, which became clear to me, immediately after posting the question.

AppleGrew
  • 9,302
  • 24
  • 80
  • 124
  • It says the Hibernate session is closed before `findPerson` returns, so the `dao` is responsible for initializing lazily-loaded collections. Reading more of the documentation, I see that the `dao` is responsible "for most of SessionFactory‘s common operations", which presumably includes opening the session. It seems to me you are expecting too much of the Dropwizard documentation if you are unfamiliar with how Hibernate works, so in your case I think you must either read Hibernate documentation or wait for a LazyInitializationException to study the problem further. – DavidS May 03 '16 at 22:29

1 Answers1

2

First The Hibernate session is closed before your resource method’s return value. How is this possible? This would have been possible had there been a try-finally block around my resource's return statement, but that is not the case here.

I know nothing about Dropwizard. So let's see the source (I change it a bit).

From UnitOfWorkAwareProxyFactory

class UnitOfWorkAwareProxyFactory {

public <T> T create(Class<T> clazz) {
        final ProxyFactory factory = new ProxyFactory();
        factory.setSuperclass(clazz);

        final Proxy proxy = (Proxy) factory.createClass().newInstance();

        proxy.setHandler(new MethodHandler() {
            @Override
            public Object invoke(Object self, Method overridden, 
                    Method proceed, Object[] args) {
                final UnitOfWork unitOfWork = overridden.getAnnotation(UnitOfWork.class);
                final UnitOfWorkAspect unitOfWorkAspect = new UnitOfWorkAspect(sessionFactories);
                try {
                    unitOfWorkAspect.beforeStart(unitOfWork);
                    Object result = proceed.invoke(self, args);
                    unitOfWorkAspect.afterEnd();
                    return result;
                } catch (Exception e) {
                    unitOfWorkAspect.onError();
                    throw e;
                }
            }
        });
        return (T) proxy;
}

}

if you have a class

class PersonDao {

    @UnitOfWork
    public Person findPerson(LongParam id) {
        return dao.findById(id.get());
    }

}

You can do something like this

UnitOfWorkAwareProxyFactory factory = new UnitOfWorkAwareProxyFactory();

PersonDao proxy = factory.create(PersonDao.class);

when you do

Person person = proxy.findPerson(1L);

that line becomes

unitOfWorkAspect.beforeStart(unitOfWork);
Object result = findPerson.invoke(proxy, 1L);
unitOfWorkAspect.afterEnd();

return result;  

Methods unitOfWorkAspect.beforeStart(unitOfWork) and unitOfWorkAspect.afterEnd() from the source UnitOfWorkAspect

class UnitOfWorkAspect {

    public void beforeStart(UnitOfWork unitOfWork) {
        session = sessionFactory.openSession();

        configureSession();
        beginTransaction();
    }

    public void afterEnd() {
        try {
            commitTransaction();
        } catch (Exception e) {
            rollbackTransaction();
            throw e;
        } finally {
            session.close();
        }

    }
}

The most important part - which means your resource method (or DAO) is responsible for initializing all lazily-loaded collections, etc., before returning. I have no Hibernate experience. I am using it for the first time now. How do I initialize, or rather what is exactly is meant by "initialize" in context of Hibernate?

Initialize in this context means the collection data should be loaded from a database. Some methods of an initialization

1.Use an eager loading, for an example

class User {

  @ManyToMany(fetch = FetchType.EAGER)
  private List<Role> roles; 

}

Hibernate will load roles via joins or subselects, when you get a User entity.

  1. Use Hibernate.initialize(user.getRoles())
  2. Use join fetch in HQL — from User user left join fetch user.roles
  3. Use Criteria with setFetchMode()
  4. Use fetch profiles, entity graphs. Don't know can entity graphs be used with a session, it is a JPA feature: http://docs.jboss.org/hibernate/orm/5.1/userguide/html_single/chapters/fetching/Fetching.html
  5. If you don't need to fetch collections, you can use a partial objects loading with transforming to the root entity: How to transform a flat result set using Hibernate
Community
  • 1
  • 1
v.ladynev
  • 19,275
  • 8
  • 46
  • 67
  • Thanks a lot. However, in Dropwizard it is not the DAO's method that is decorated with `@UnitOfWork`, rather those are Jersey resources methods, which are decorated with this annotation. They in-turn access the DAOs. Nonetheless, in my case I have a `@OneToMany` relation (`user.getEmails()`). Weirdly accessing this `getEmails()` **sometimes** result into `LazyInitializationException`. Since this whole code is invoked during `proceed.invoke(self, args);`, so Hibernate session must exist. So, probably the only reason for this error would be that `user` is sometimes getting detached. But why? – AppleGrew May 04 '16 at 18:40
  • @AppleGrew By default a session is bound to the current thread, so getting `user.getEmails()` in other thread can be a reason. Anyway, in my opinion, better to ininitialize all lazy data while getting `user` (for an example, using `left join fetch`). – v.ladynev May 04 '16 at 20:58