Hibernate bootstrapping

In this article, I will introduce you the new native bootstrapping API of Hibernate 5.

What is bootstrapping good for?

If you ever felt like you need more control over Hibernate’s internal configuration this new feature is something you can leverage to achieve this goal. And this is useful if you have a simple project which only needs to use Hibernate and no other JPA framework: with the help of the bootstrapping API you can get your project up-and-running without much magic.

Naturally, every rose has its thorn: the usage of the new native bootstrapping API makes the configuration more complex but it is more powerful than the JPA bootstrapping API.

Why is this better than previously?

The new features introduced to enable you access to the API through Java code. This means you don’t have to rely on sole XML configuration, you can add some configuration in your codebase which can only change if you deliver a new version of the software.

In some cases, this is very useful because your application doesn’t have to rely on the rightness of the properties configured through the configuration files – or you can tweak some internal configuration in Hibernate which you don’t want to change through an external file.

How to use the API?

To get started, you need the right dependencies in your project. As for all the examples in this article series, I’m using Hibernate version 5.3.6. Final and H2 version 1.4.197.

We need to create a StandardServiceRegistry, a Metadata object and use this to initiate a SessionFactory.

hibernate.cfg.xml

Most of the time, I use an XML based configuration file, hibernate.cfg.xml to set-up the StandardServiceRegistry:

<hibernate-configuration>
    <session-factory>
        <!-- Database connection settings -->
        <property name="connection.driver_class">org.h2.Driver</property>
        <property name="connection.url">jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE</property>
        <property name="connection.username">sa</property>
        <property name="connection.password"/>

        <!-- JDBC connection pool (use the built-in) -->
        <property name="connection.pool_size">1</property>

        <!-- SQL dialect -->
        <property name="dialect">org.hibernate.dialect.H2Dialect</property>

        <!-- Echo all executed SQL to stdout -->
        <property name="show_sql">true</property>

        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">create</property>

        <mapping class="hibernate_example.Book"/>
    </session-factory>
</hibernate-configuration>

Using this file makes the configuration independent of the source code and gives you an overview of the configuration in a structured manner.

final Configuration configuration = new Configuration().configure();
final StandardServiceRegistryBuilder builder = new StandardServiceRegistryBuilder().configure(“hibernate.cfg.xml”);

As you can see in the example code, you need to tell Hibernate that you’re using the hibernate.cfg.xml file. In previous versions of Hibernate, you didn’t need to specify that you’re using this file to set-up your service registry because this was the default behavior.

Programmatic configuration

With Hibernate 5, you’ve got the option of a programmatic configuration of the ORM in Java code.

Let’s see, how we can map the previously shown hibernate.cfg.xml file into Java code. For this, I’ve created a class named HibernateUtil which looks like this:

package hibernate_example;

import java.util.Properties;

import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;

/**
 * Utility class for bootstrapping Hibernate through Java code only.
 *
 * @author GHajba
 */
public class HibernateUtil {

    protected HibernateUtil() {
    }

    public static SessionFactory createSessionFactory() {
        MetadataSources metadataSources = new MetadataSources(configureServiceRegistry());
        addClasses(metadataSources);
        return metadataSources.buildMetadata()
                .getSessionFactoryBuilder()
                .build();
    }

    private static ServiceRegistry configureServiceRegistry() {
        return new StandardServiceRegistryBuilder()
                .applySettings(getProperties())
                .build();
    }

    private static Properties getProperties() {
        Properties properties = new Properties();
        properties.put("hibernate.connection.driver_class", "org.h2.Driver");
        properties.put("hibernate.connection.url", "jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE");
        properties.put("hibernate.connection.username", "sa");
        properties.put("hibernate.connection.password", "");
        properties.put("hibernate.connection.pool_size", 1);
        properties.put("hibernate.dialect", "org.hibernate.dialect.H2Dialect");
        properties.put("hibernate.show_sql", "true");
        properties.put("hibernate.hbm2ddl.auto", "create");
        properties.put("", "");
        return properties;
    }

    private static void addClasses(MetadataSources metadataSources) {
        metadataSources.addAnnotatedClass(Book.class);
    }
}

As you can see, everything is now in Java code. This makes it convenient to only deal with Java classes – but think about what you get if you have a lot of entities? In my opinion, it will mess-up your codebase like in the following screenshot:

Therefore, I prefer keeping the configuration in separate files, not in the Java code – but this is my personal opinion.

hibernate.properties

One option to let your code breathe is to extract the configuration into a properties file – which is most of the time called hibernate.properties.

Using the example above, we can extract the configuration into the following file:

hibernate.connection.driver_class=org.h2.Driver
hibernate.connection.url=jdbc:h2:mem:db1;DB_CLOSE_DELAY=-1;MVCC=TRUE
hibernate.connection.username=sa
hibernate.connection.password=
hibernate.connection.pool_size=1
hibernate.dialect=org.hibernate.dialect.H2Dialect
hibernate.show_sql=true
hibernate.hbm2ddl.auto=create

Now, we have to adapt the HibernateUtil class too to use this new file:

package hibernate_example;

import java.io.IOException;
import java.util.Properties;

import org.hibernate.SessionFactory;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;
import org.hibernate.service.ServiceRegistry;

/**
 * Utility class for bootstrapping Hibernate through Java code and hibernate.properties file.
 *
 * @author GHajba
 */
public class HibernateUtil {

    protected HibernateUtil() {
    }

    public static SessionFactory createSessionFactory() {
        MetadataSources metadataSources = new MetadataSources(configureServiceRegistry());
        addClasses(metadataSources);
        return metadataSources.buildMetadata()
                .getSessionFactoryBuilder()
                .build();
    }

    private static ServiceRegistry configureServiceRegistry() {
        return new StandardServiceRegistryBuilder()
                .applySettings(getProperties())
                .build();
    }

    private static Properties getProperties() {
        Properties properties = new Properties();
        try {
            properties.load(HibernateUtil.class
                    .getResourceAsStream("/hibernate.properties"));
        } catch (IOException e) {
            throw new RuntimeException(e);
        }
        return properties;
    }

    private static void addClasses(MetadataSources metadataSources) {
        metadataSources.addAnnotatedClass(Book.class);
    }
}

Conclusion

Using the bootstrapping API you can configure your Hibernate application – this makes your project more complex but you can hide away these features in a service class. This comes handy if you only want to use Hibernate in your simple project.

If you look closely to the example applications delivered with this article-series you can see that I myself use this API to get the applications running with Hibernate.

2 Comments

  1. Really helpfull. This is what I was expecting for bootstrapping hibernate/jpa without persistnce.xml
    I changed it only a little, adding

    public static EntityManager createEntityManager()
    {
    return createSessionFactory().createEntityManager();
    }

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.