Search This Blog

Sunday 11 November 2012

Forcefully initializing proxies in Hibernate

As we have seen, The Hibernate Entities that we load in a persistence context may be made of proxies and collection wrappers. The simplest way to initialize these proxies would be to call any of the data getter methods (except Identifier).
Consider that you have loaded an object. You now need to detach the object and return it to a different function outside the persistence context.
public static void test() {
    Session session = sessionFactory.openSession();
    System.out.println("Loading a shelf object");
    Shelf shelf = (Shelf) session.load(Shelf.class, shelfId);
    session.close();
    useDetached(shelf);
}
    
public static void useDetached(Shelf shelf) {
    //do operations here
    System.out.println("Shelf code is " + shelf.getCode());
}
The above code results in the infamous exception
Exception in thread "main" org.hibernate.LazyInitializationException: could not
initialize proxy - no Session
The way around would be to initialize the entities needed.
public static void test() {
    Session session = sessionFactory.openSession();
    System.out.println("Loading a shelf object");
    Shelf shelf = (Shelf) session.load(Shelf.class, shelfId);
    shelf.getCode();// this will load the object
    session.close();
    useDetached(shelf);
}
This will make the code work, but looks very stupid and will frankly cause some other developer to curse you one day. Hibernate provides a better method to initialize objects. Hibernate.initialize()
public static void testInitializeProxy() {
    Session session = sessionFactory.openSession();
    System.out.println("Loading a shelf object");
    Shelf shelf = (Shelf) session.load(Shelf.class, shelfId);
    System.out.println("calling Hibernate.initialize() on the shelf");
    Hibernate.initialize(shelf);
    System.out.println("executed Hibernate.initialize() on shelf");
    session.close();
}
The logs are as below:
Loading a shelf object
calling Hibernate.initialize() on the shelf
Hibernate: 
    /* load com.collection.smart.Shelf */ 
     select
        shelf0_.ID as ID0_0_,
        shelf0_.CODE as CODE0_0_ 
    from
        SHELF shelf0_ 
    where
        shelf0_.ID=?
executed Hibernate.initialize() on shelf

This method is a very rare necessity. To lazily initialize a collection:
public static void testInitializeCollection() {

    Session session = sessionFactory.openSession();
    Shelf shelf = (Shelf) session.load(Shelf.class, shelfId);
    Set<Book> books = shelf.getAllBooks();
    System.out.println("calling Hibernate.initialize() on set ");
    Hibernate.initialize(books);
    System.out.println("executed Hibernate.initialize() on the set ");
    session.close();
    for(Book book: books) {
        System.out.println("Book class is " + book.getClass());
    }    
}
The logs indicate the output:
Hibernate: 
    /* load com.collection.smart.Shelf */ 
    select
        shelf0_.ID as ID0_0_,
        shelf0_.CODE as CODE0_0_ 
    from
        SHELF shelf0_ 
    where
        shelf0_.ID=?
calling Hibernate.initialize() on set 
Hibernate: 
    /* load one-to-many com.collection.smart.Shelf.allBooks */ 
     select
        allbooks0_.SHELF_ID as SHELF3_1_,
        allbooks0_.ID as ID1_,
        allbooks0_.ID as ID1_0_,
        allbooks0_.Name as Name1_0_,
        allbooks0_.shelf_id as shelf3_1_0_ 
    from
        BOOK allbooks0_ 
    where
        allbooks0_.SHELF_ID=?
executed Hibernate.initialize() on the set 
Book class is class com.collection.smart.Book
Book class is class com.collection.smart.Book
For the collection scenario the java docs comes with a warning:
Note: This only ensures initialization of a proxy object or collection; it is not guaranteed that the elements INSIDE the collection will be initialized/materialized. 
In our case, as the SQL Query was executed the records were initialized successfully. I even used a smart collection to see if the entities would be loaded. However in that case too, on calling the initialize method Hibernate loaded all the Book entities and not Book proxies.

1 comment:

  1. How can I call Hibernate.initialize when using the built-in Hibernate provider from JBoss Wildfly? Should I add the Hibernate library to the project though?

    ReplyDelete