Hibernate initialize() – force initialization of proxy/collections

As you know that hibernate does not support lazy initialization for detached objects. Typically, you load an entity using hibernate session and work-through it and then close the session. After closing the session, entity becomes detached entity, so it cannot make further calls to database until again associated with a new session.

But loading whole entity and it’s associated entities/collections is never a good idea so hibernate allows you to lazy load the data when needed. But what if – you need to access data at some other place outside transaction boundary and hibernate session will be closed by then.

1. Why we need to initialize

A LazyInitializationException will be thrown by Hibernate if an uninitialized collection or proxy is accessed outside of the scope of the Session, i.e., when the entity owning the collection or having the reference to the proxy is in the detached state.

Well you got few approaches. Let’s list them down first:

  • Use eager initialization

    This is easy approach but most dangerous if not used carefully. It has the potential to bring down your whole application in runtime if there are cyclic dependencies between entities. My suggestion – never use it until you are absolutely sure of it.

  • Do not close the session until job is done

    This is another easy approach. But it forces the database connection to keep open until job is done. It can reduce the application performance considerably.

  • Fetch required data in DAO before session is closed or open new session

    This is most appropriate approach in most of the cases. When you know what data you will need next, just load it before closing the session. Or open a new session when you really need that data.

You can use <property name="hibernate.enable_lazy_load_no_trans">true</property> OR ENABLE_LAZY_LOAD_NO_TRANS, if you don’t want to make any code change and bypass all lazy load related issues. This setting will load proxy entity and collection in detached entities as well. BUT USE IT WITH CAUTION. You will not be able to port your project to other JPA provider if needed. You also can have the N+1 effect. Also everytime you will get the latest version of the data, which may not be desired in some cases.

2. Using Hibernate.initialize() to initialize proxy/collection

Sometimes a proxy or collection needs to be initialized before closing the Session. One way is to force initialization by calling entity.getXXX() or entity.getXXX().size(), for example. However, this can be confusing to readers of the code and it is not convenient for generic code.

The static methods Hibernate.initialize() and Hibernate.isInitialized(), provide the application with a convenient way of working with lazily initialized collections or proxies. Hibernate.initialize(entity.getXXX()) will force the initialization of a proxy, entity.getXXX(), as long as its Session is still open. Hibernate.initialize( ) has a similar effect for the collection of entities as well.

e.g. If we have two entity types Student and Department, then we can easily initialize lazy load enabled collection of students like below:

Department dept = (Department) session.get(Department.class, deptId);

//*****Initialize student collection*******
Hibernate.initialize(dept.getStudents());

Above code will immediately, load the collection of students. Now you are safe to close the session and you will be able to get data as and when required. It’s much cleaner way of pre-initializing lazy load enabled proxy or collection objects.

3. Hibernate initialize() Example

I have quickly written an example with two entities and used Hibernate.initialize(). Let’s see the files:

pom.xml

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd;
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.howtodoinjava</groupId>
    <artifactId>HibernateExamples</artifactId>
    <version>0.0.1-SNAPSHOT</version>
    <packaging>jar</packaging>

    <name>HibernateExamples</name>
    <url>http://maven.apache.org</url>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>

    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>2.3.2</version>
                <configuration>
                    <source>1.7</source>
                    <target>1.7</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
    <dependencies>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <!-- for JPA, use hibernate-entitymanager instead of hibernate-core -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-entitymanager</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <!-- optional -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-osgi</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-envers</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-c3p0</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-proxool</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-infinispan</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-ehcache</artifactId>
            <version>4.3.6.Final</version>
        </dependency>
        <dependency>
            <groupId>antlr</groupId>
            <artifactId>antlr</artifactId>
            <version>2.7.6</version>
        </dependency>
        <dependency>
            <groupId>commons-collections</groupId>
            <artifactId>commons-collections</artifactId>
            <version>3.1</version>
        </dependency>
        <dependency>
            <groupId>dom4j</groupId>
            <artifactId>dom4j</artifactId>
            <version>1.6.1</version>
        </dependency>
        <dependency>
            <groupId>javassist</groupId>
            <artifactId>javassist</artifactId>
            <version>3.4.GA</version>
        </dependency>
        <dependency>
            <groupId>javax.transaction</groupId>
            <artifactId>jta</artifactId>
            <version>1.1</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-api</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.slf4j</groupId>
            <artifactId>slf4j-log4j12</artifactId>
            <version>1.5.6</version>
        </dependency>
        <dependency>
            <groupId>org.hsqldb</groupId>
            <artifactId>hsqldb</artifactId>
            <version>2.2.9</version>
        </dependency>
    </dependencies>
</project>

hibernate.cfg.xml

<?xml version="1.0" encoding="utf-8"?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD 3.0//EN"
"http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <property name="hibernate.archive.autodetection">class,hbm</property>  
        <property name="hibernate.dialect">org.hibernate.dialect.HSQLDialect</property>  
        <property name="hibernate.show_sql">true</property>    
        <property name="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</property>    
        <property name="hibernate.connection.username">sa</property>    
        <property name="hibernate.connection.password"></property>    
        <property name="hibernate.connection.url">jdbc:hsqldb:mem:howtodoinjava</property>    
        <property name="hibernate.hbm2ddl.auto">create</property>    
        <mapping class="com.howtodoinjava.demo.entity.Department"></mapping>
        <mapping class="com.howtodoinjava.demo.entity.Student"></mapping>
    </session-factory>
</hibernate-configuration>

Department.java

@Entity
public class Department {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;

    private String name;

    @OneToMany(mappedBy = "department")
    @OrderBy("name ASC")
    private List<Student> students;

    public Department() {
        students = new ArrayList<Student>();
    }

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String deptName) {
        this.name = deptName;
    }

    public void addStudent(Student student) {
        if (!getStudents().contains(student)) {
            getStudents().add(student);
            if (student.getDepartment() != null) {
                student.getDepartment().getStudents().remove(student);
            }
            student.setDepartment(this);
        }
    }

    public Collection<Student> getStudents() {
        return students;
    }

    public String toString() {
        return "Department id: " + getId() + ", name: " + getName();
    }
}

Student.java

@Entity
public class Student {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private int id;
    private String name;

    @ManyToOne
    private Department department;

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Department getDepartment() {
        return department;
    }

    public void setDepartment(Department department) {
        this.department = department;
    }

    public String toString() {
        return "Student id: " + getId() + " name: " + getName() + " with "
                + getDepartment();
    }
}

HibernateUtil.java

public class HibernateUtil
{
   private static SessionFactory sessionFactory = buildSessionFactory();
 
   private static SessionFactory buildSessionFactory()
   {
      try
      {
         if (sessionFactory == null)
         {
            Configuration configuration = new Configuration().configure(HibernateUtil.class.getResource("/hibernate.cfg.xml"));
            StandardServiceRegistryBuilder serviceRegistryBuilder = new StandardServiceRegistryBuilder();
            serviceRegistryBuilder.applySettings(configuration.getProperties());
            ServiceRegistry serviceRegistry = serviceRegistryBuilder.build();
            sessionFactory = configuration.buildSessionFactory(serviceRegistry);
         }
         return sessionFactory;
      } catch (Throwable ex)
      {
         System.err.println("Initial SessionFactory creation failed." + ex);
         throw new ExceptionInInitializerError(ex);
      }
   }
 
   public static SessionFactory getSessionFactory()
   {
      return sessionFactory;
   }
 
   public static void shutdown()
   {
      getSessionFactory().close();
   }
}

TestHibernate.java

public class TestHibernate {
    public static void main(String[] args) {
        // Set pre-requisite data as it's in-memory database
        Session session1 = HibernateUtil.getSessionFactory().openSession();
        session1.beginTransaction();
        Integer deptId = setupDB(session1);
        session1.getTransaction().commit();
        session1.close();

        // Get Department Entity
        Session session2 = HibernateUtil.getSessionFactory().openSession();
        Department dept = (Department) session2.get(Department.class, deptId);

        //*****Initialize student collection*******
        Hibernate.initialize(dept.getStudents());
        session2.close();
        
        HibernateUtil.shutdown();
    }

    private static Integer setupDB(Session session) {
        Student student1 = new Student();
        student1.setName("Lokesh");
        session.save(student1);

        Student student2 = new Student();
        student2.setName("Amit");
        session.save(student2);

        Department dept = new Department();
        dept.setName("HR");
        dept.addStudent(student1);
        dept.addStudent(student2);
        session.save(dept);

        return dept.getId();
    }
}

Output of the program is as below:

Hibernate: alter table Student drop constraint FK_58v5l5agiw84dedkhh57vdb9l
Hibernate: drop table Department if exists
Hibernate: drop table Student if exists
Hibernate: create table Department (id integer generated by default as identity (start with 1), name varchar(255), primary key (id))
Hibernate: create table Student (id integer generated by default as identity (start with 1), name varchar(255), department_id integer, primary key (id))
Hibernate: alter table Student add constraint FK_58v5l5agiw84dedkhh57vdb9l foreign key (department_id) references Department
Hibernate: insert into Student (id, department_id, name) values (default, ?, ?)
Hibernate: insert into Student (id, department_id, name) values (default, ?, ?)
Hibernate: insert into Department (id, name) values (default, ?)
Hibernate: update Student set department_id=?, name=? where id=?
Hibernate: update Student set department_id=?, name=? where id=?
Hibernate: select department0_.id as id1_0_0_, department0_.name as name2_0_0_ from Department department0_ where department0_.id=?
Hibernate: select students0_.department_id as departme3_0_0_, students0_.id as id1_1_0_, students0_.id as id1_1_1_, students0_.department_id as departme3_1_1_, students0_.name as name2_1_1_ from Student students0_ where students0_.department_id=? order by students0_.name asc

Drop me you comments and questions in comments section below.

Happy Learning !!

Was this post helpful?

Join 7000+ Fellow Programmers

Subscribe to get new post notifications, industry updates, best practices, and much more. Directly into your inbox, for free.

0 thoughts on “Hibernate initialize() – force initialization of proxy/collections”

Leave a Comment

HowToDoInJava

A blog about Java and its related technologies, the best practices, algorithms, interview questions, scripting languages, and Python.