Hibernate JBoss – An example application

In this article, we will introduce Hibernate ORM, which is the de facto standard object-relational mapping framework for Java applications. At the end of it, you will learn how to develop Hibernate applications on top of JBoss / WildFly.

Introducing Hibernate

Hibernate provides a bridge between the database and the application by persisting application objects in the database, rather than requiring the developer to write and maintain lots of code to store and retrieve objects.

You can develop applications with Hibernate in two ways:

  • Standalone Java application. This way, you will include the hibernate dependencies in your project, use the org.hibernate packages in your code and include the Hibernate configuration file (hibernate.cfg.xml).
  • Jakarta EE application. This way, Hibernate can be used as Java Persistence API implementation. You will use the jakarta.jpa packages and use the persistence.xml file as configuration.

For an example of standalone Java application with Hibernate check this article: Setting up an Hibernate project with Maven

In this article we will show how to use Hibernate as Persistence Layer for a Jakarta EE application that we will deploy on WildFly.

Create the Hibernate Project

Firstly, create a new Maven project with the following archetype:

mvn archetype:generate -DgroupId=com.sample -DartifactId=hibernate-demo -DarchetypeArtifactId=maven-archetype-quickstart -DinteractiveMode=false

Next, you can import the project in your favourite IDE, for example import it into IntelliJ Idea:

Then, from the Top Menu choose: File | Open and point to your project “hibernate-demo”.

Finally, modify your pom.xml to include the Jakarta EE dependency and Java 11 as Source and Target build:

<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/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.sample</groupId>
  <artifactId>hibernate-demo</artifactId>
  <packaging>war</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>hibernate-demo</name>
  <url>http://maven.apache.org</url>
  <properties>
    <maven.compiler.target>11</maven.compiler.target>
    <maven.compiler.source>11</maven.compiler.source>
  </properties>
  <dependencies>
    <dependency>
      <groupId>jakarta.platform</groupId>
      <artifactId>jakarta.jakartaee-api</artifactId>
      <version>8.0.0</version>
      <scope>provided</scope>
    </dependency>
    <dependency>
      <groupId>com.github.javafaker</groupId>
      <artifactId>javafaker</artifactId>
      <version>1.0.2</version>
    </dependency>
  </dependencies>
</project>

We also have added the JavaFaker library. This is only for testing purpose, to generate random data for our Entity.

Next, we will now add some Classes.

Coding the Model

Firstly, we will be adding the Model for our application. Add the following Employee Class to your project:

hibernate jboss

Here is the source code:

@Entity
@Table 
public class Employee {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    @Column(name = "id")
    private int id;

    @Column(name = "fistName")
    private String firstName;

    @Column(name = "lastName")
    private String lastName;

    @Column(name = "dept")
    private String dept;

    public Employee() {

    }

    public Employee(int id, String firstName, String lastName, String dept) {
        this.setId(id);
        this.setFirstName(firstName);
        this.setLastName(lastName);
        this.setDept(dept);
    }

   // Getter/Setters omitted for brevity
}

The Employee Class is an Entity which maps a Database table. If you don’t provide a parameter to the @Table annotation, it will use by default a Table name with the same name of your Class.

The Employee has an “id” as Primary Key which is auto-generated. Please note the GenerationType.IDENTITY means it relies on an auto-incremented database column and lets the database generate a new value with each insert operation.

Coding the Service Class

To access the Model and persist data, we need a Component which is able to begin a Transaction. EJB are by default transactional. Also CDI Beans can be transactional if you decorate them with the @Transactional annotation.

Here is the EmployeeService Class:

@ApplicationScoped
public class EmployeeService {
    @PersistenceContext
    private EntityManager em;

    @Transactional
    public void saveEmployee(Employee e)  {
        em.persist(e);
    }
    
    public List<Employee> findEmployees()  {
    	Query query = em.createQuery("FROM Employee");

        List <Employee> list = query.getResultList();
        return list;
    }
}

The EmployeeService Class relies on the default PersistenceContext to inject the EntityManager. The EntityManager implements the programming interfaces and lifecycle rules defined by the JPA specification. In the next part of this tutorial we will learn how to use directly the Hibernate Session to manage data.

Coding the Controller

Finally, to access the application remotely, we will add a simple Servlet Class. The Servlet will be in charge to invoke the EmployeeService.

@WebServlet("/HelloWorld")
public class DemoServlet extends HttpServlet {

    static String PAGE_HEADER = "<html><head><title>Hello Hibernate</title></head><body>";

    static String PAGE_FOOTER = "</body></html>";

    @Inject
    EmployeeService service;

    @Override
    protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
        resp.setContentType("text/html");
        PrintWriter writer = resp.getWriter();
        writer.println(PAGE_HEADER);
        
        service.saveEmployee(randomEmployee());
        writer.println("<h1>Employee List</h1>");
        List<Employee> list = service.findEmployees();
        writer.println("<ul>");
        for (Employee e:list)
        	writer.println("<li>" +e.toString()+"</li>");
        writer.println("</ul>");

        writer.println(PAGE_FOOTER);
        writer.close();
    }
    
    Employee randomEmployee()  {
       Faker fake = new Faker();
       Employee employee = new Employee();
       employee.setFirstName(fake.name().firstName());
       employee.setLastName(fake.name().lastName());
       employee.setDept(fake.job().position());
       return employee;
    }
}

Please notice we are using the com.github.javafaker.Faker Class to generate random data for our Employee.

Configuring the Persistence Unit

When running Hibernate in a managed environment (such as WildFly), the Persistence Unit is configured through the persistence.xml file which can reference a JDBC Connection or a Datasource object. The following persistence.xml relies on the Default H2 Database of WildFly:

<persistence version="2.1"
             xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
             xsi:schemaLocation="
        http://xmlns.jcp.org/xml/ns/persistence
        http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
    <persistence-unit name="primary">
        <!-- If you are running in a production environment, add a managed
           data source, this example data source is just for development and testing! -->
        <!-- The datasource is deployed as WEB-INF/kitchensink-quickstart-ds.xml, you
           can find it in the source at src/main/webapp/WEB-INF/kitchensink-quickstart-ds.xml -->
        <jta-data-source>java:jboss/datasources/ExampleDS</jta-data-source>
        <properties>
            <!-- Properties for Hibernate -->
            <property name="hibernate.hbm2ddl.auto" value="create-drop" />
            <property name="hibernate.show_sql" value="false" />
        </properties>
    </persistence-unit>
</persistence>

Please note the property hibernate.hbm2ddl.auto drops the schema when the Hibernate SessionFactory is closed explicitly. This typically happens when the application is stopped.

Running the application

Build your application and deploy it on WildFly. You can test it by accessing the Servlet:

hibernate jboss

Using Hibernate API

In our example, we have used the javax.persistence (or jakarta.persistence for Jakarta EE 9/10) packages to persist and fetch data. To use the underlying persistence implementation, access the Hibernate Session with the getDelegate method of the EntityManager:

@Transactional
public void saveEmployeeHibernate(Employee e) throws Exception {

    // using Hibernate session(Native API) and JPA entitymanager
    Session session = (Session) em.getDelegate();       
    session.persist(e);
 
}

The org.hibernate.Session Class is not available in the Jakarta EE dependency. Therefore, in order to compile it, add it in your pom.xml with scope “provided”. That means, the dependency will be provided at runtime by the container:

<dependency>
    <groupId>org.hibernate</groupId>
    <artifactId>hibernate-core</artifactId>
    <scope>provided</scope>
    <version>6.0.0.Final</version>
</dependency>

By using the Hibernate Session, you can perform the equivalent operations you can do with JPA:

Query query = session.createQuery("FROM Employee");

On the other hand, if you need to refer to API which are only available in the org.hibernate packages (and not in the JPA API), then you have to remove the scope “provided”. For example to find which version of Hibernate you are using, you can use the following code:

String hibernateVersion = org.hibernate.annotations.common.Version.getVersion();
System.out.println("Hibernate Version: "+ hibernateVersion);

Source code: The source code for this tutorial is available here: https://github.com/fmarchioni/mastertheboss/tree/master/hibernate/hibernate-demo