Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What Dropwizard-Hibernate doc is trying to say?

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.

like image 311
AppleGrew Avatar asked Jan 17 '26 19:01

AppleGrew


1 Answers

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
like image 59
v.ladynev Avatar answered Jan 20 '26 10:01

v.ladynev



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!