Hibernate Component Mapping Example Tutorial

This tutorial will guide you through setting up and demonstrating component mapping in Hibernate 6 with Java 21. We'll create a simple application that maps a component class to an entity class, demonstrating how to use complex types as components in Hibernate.

Introduction

Component mapping in Hibernate allows you to embed value-type objects (components) in entity classes. These components do not have their own lifecycle and are persisted as part of the owning entity. Component mapping is useful for modeling complex types that logically belong to a single entity.

In this tutorial, we will:

  1. Set up a Maven project with Hibernate and an H2 database dependency.
  2. Configure Hibernate.
  3. Create entity and component classes (Product and ProductDetails).
  4. Implement component mapping.
  5. Demonstrate component mapping with a sample application.

Step 1: Set Up Your Project

1.1 Create a Maven Project

Open your IDE and create a new Maven project.

1.2 Add Dependencies

Update your pom.xml file to include the necessary dependencies for Hibernate and H2 (an in-memory database for simplicity).

<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.example</groupId>
    <artifactId>hibernate-component-mapping-example</artifactId>
    <version>1.0-SNAPSHOT</version>

    <dependencies>
        <!-- Hibernate ORM -->
        <dependency>
            <groupId>org.hibernate.orm</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.4.0.Final</version>
        </dependency>

        <!-- H2 Database -->
        <dependency>
            <groupId>com.h2database</groupId>
            <artifactId>h2</artifactId>
            <version>2.1.214</version>
        </dependency>
    </dependencies>

    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.maven.plugins</groupId>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.10.1</version>
                <configuration>
                    <source>21</source>
                    <target>21</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

1.3 Configure Hibernate

Create a file named hibernate.cfg.xml in the src/main/resources directory to configure Hibernate. This file contains the database connection settings and Hibernate properties.

<!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.dialect">org.hibernate.dialect.H2Dialect</property>
        <property name="hibernate.connection.driver_class">org.h2.Driver</property>
        <property name="hibernate.connection.url">jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1</property>
        <property name="hibernate.connection.username">sa</property>
        <property name="hibernate.connection.password"></property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="hibernate.show_sql">true</property>
    </session-factory>
</hibernate-configuration>

Explanation:

  • hibernate.dialect specifies the SQL dialect to be used.
  • hibernate.connection.driver_class specifies the JDBC driver class.
  • hibernate.connection.url specifies the JDBC URL for the database connection.
  • hibernate.connection.username and hibernate.connection.password specify the database credentials.
  • hibernate.hbm2ddl.auto specifies the schema generation strategy.
  • hibernate.show_sql specifies whether to show SQL statements in the logs.

Step 2: Create the Entity and Component Classes

2.1 Create the ProductDetails Component Class

Create a component class ProductDetails that will be embedded in the Product entity class.

package com.example.entity;

import jakarta.persistence.Embeddable;

@Embeddable
public class ProductDetails {
    private String manufacturer;
    private String warranty;

    // Getters and setters
    public String getManufacturer() {
        return manufacturer;
    }

    public void setManufacturer(String manufacturer) {
        this.manufacturer = manufacturer;
    }

    public String getWarranty() {
        return warranty;
    }

    public void setWarranty(String warranty) {
        this.warranty = warranty;
    }
}

Explanation:

  • The @Embeddable annotation specifies that the class can be embedded in an entity.

2.2 Create the Product Entity Class

Create an entity class Product that will use the ProductDetails component.

package com.example.entity;

import jakarta.persistence.Embedded;
import jakarta.persistence.Entity;
import jakarta.persistence.GeneratedValue;
import jakarta.persistence.GenerationType;
import jakarta.persistence.Id;

@Entity
public class Product {
    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;
    private String name;
    private double price;

    @Embedded
    private ProductDetails productDetails;

    // Getters and setters
    public Long getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

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

    public double getPrice() {
        return price;
    }

    public void setPrice(double price) {
        this.price = price;
    }

    public ProductDetails getProductDetails() {
        return productDetails;
    }

    public void setProductDetails(ProductDetails productDetails) {
        this.productDetails = productDetails;
    }
}

Explanation:

  • The @Entity annotation specifies that the class is an entity and is mapped to a database table.
  • The @Id annotation specifies the primary key of the entity.
  • The @GeneratedValue(strategy = GenerationType.IDENTITY) annotation specifies that the primary key is auto-incremented.
  • The @Embedded annotation specifies that the ProductDetails component should be embedded in the Product entity.

Step 3: Create the Hibernate Utility Class

Create a utility class HibernateUtil to manage the Hibernate SessionFactory. This class ensures a single instance of SessionFactory is created and provides a method to close it.

package com.example.util;

import org.hibernate.SessionFactory;
import org.hibernate.cfg.Configuration;

public class HibernateUtil {
    private static final SessionFactory sessionFactory = buildSessionFactory();

    private static SessionFactory buildSessionFactory() {
        try {
            // Create the SessionFactory from hibernate.cfg.xml
            return new Configuration().configure().buildSessionFactory();
        } catch (Throwable ex) {
            // Make sure you log the exception, as it might be swallowed
            System.err.println("Initial SessionFactory creation failed." + ex);
            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
        // Close caches and connection pools
        getSessionFactory().close();
    }
}

Explanation:

  • The buildSessionFactory method creates the SessionFactory from the hibernate.cfg.xml configuration file.
  • The getSessionFactory method returns the singleton instance of SessionFactory.
  • The shutdown method closes the SessionFactory to release resources.

Step 4: Demonstrate Component Mapping

Create a MainApp class to demonstrate component mapping functionality. This class performs CRUD operations on the Product entity, which includes the ProductDetails component.

package com.example.main;

import com.example.entity.Product;
import com.example.entity.ProductDetails;
import com.example.util.HibernateUtil;
import org.hibernate.Session;
import org.hibernate.Transaction;

public class MainApp {
    public static void main(String[] args) {
        // Create product details
        ProductDetails productDetails = new ProductDetails();
        productDetails.setManufacturer("ACME Corp");
        productDetails.setWarranty("2 years");

        // Create product
        Product product = new Product();
        product.setName("Laptop");
        product.setPrice(1500.00);
        product.setProductDetails(productDetails);

        // Save product
        saveProduct(product);

        // Retrieve and update product
        Product retrievedProduct = getProduct(product.getId());
        if (retrievedProduct != null) {
            retrievedProduct.setPrice(1400.00);
            updateProduct(retrievedProduct);
        }

        // Delete product
        deleteProduct(retrievedProduct.getId());

        // Shut down Hibernate
        HibernateUtil.shutdown();
    }

    public static void saveProduct(Product product) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction transaction = null;

        try {
            transaction = session.beginTransaction();
            session.save(product);
            transaction.commit();
            System.out.println("Product saved successfully");
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public static Product getProduct(Long id) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Product product = null;

        try {
            product = session.get(Product.class, id);
            if (product != null) {
                System.out.println("Product retrieved: " + product.getName());
            }
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            session.close();
        }

        return product;
    }

    public static void updateProduct(Product product) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction transaction = null;

        try {
            transaction = session.beginTransaction();
            session.update(product);
            transaction.commit();
            System.out.println("Product updated successfully");
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            session.close();
        }
    }

    public static void deleteProduct(Long id) {
        Session session = HibernateUtil.getSessionFactory().openSession();
        Transaction transaction = null;

        try {
            transaction = session.beginTransaction();
            Product product = session.get(Product.class, id);
            if (product != null) {
                session.delete(product);
                transaction.commit();
                System.out.println("Product deleted successfully");
            }
        } catch (Exception e) {
            if (transaction != null) {
                transaction.rollback();
            }
            e.printStackTrace();
        } finally {
            session.close();
        }
    }
}

Explanation:

  1. Create Product Details:

    ProductDetails productDetails = new ProductDetails();
    productDetails.setManufacturer("ACME Corp");
    productDetails.setWarranty("2 years");
    

    A ProductDetails component is created and its properties are set.

  2. Create Product:

    Product product = new Product();
    product.setName("Laptop");
    product.setPrice(1500.00);
    product.setProductDetails(productDetails);
    

    A Product entity is created and its properties, including the ProductDetails component, are set.

  3. Save Product:

    saveProduct(product);
    

    The saveProduct method is called to save the Product entity, including the ProductDetails component.

  4. Retrieve and Update Product:

    Product retrievedProduct = getProduct(product.getId());
    if (retrievedProduct != null) {
        retrievedProduct.setPrice(1400.00);
        updateProduct(retrievedProduct);
    }
    

    The getProduct method is called to retrieve the Product entity by its ID. If the product is found, its price is updated and the updateProduct method is called to save the changes.

  5. Delete Product:

    deleteProduct(retrievedProduct.getId());
    

    The deleteProduct method is called to delete the Product entity by its ID.

  6. Shut Down Hibernate:

    HibernateUtil.shutdown();
    

    The shutdown method is called to close the SessionFactory and release resources.

Sample Output

When you run the MainApp class, you should see the following output:

Product saved successfully
Product retrieved: Laptop
Product updated successfully
Product deleted successfully

This output indicates that the product was successfully saved, retrieved, updated, and deleted, demonstrating the functionality of component mapping in Hibernate.

Conclusion

In this tutorial, we have successfully demonstrated how to use component mapping in Hibernate. We set up a Hibernate project, created entity and component classes, and implemented component mapping functionality. This guide provides a solid foundation for modeling complex types as components in your Hibernate-based applications.

Comments