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.
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.
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 SessionThe 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 shelfThis 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.BookFor 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.
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