Hibernate/JPA MappedSuperclass Inheritance Example

JPA/Hibernate support 4 inheritance strategies that map the domain objects to different table structures. 
The JPA standard specification defines the @MappedSuperclass annotation to allow an entity to inherit properties from a base class.
From a database perspective, the @MappedSuperclass inheritance model is invisible since all the base class properties are simply copied to the database table mapped by the actual entity class.

Example: @MappedSuperclass inheritance

In the following domain model class hierarchy, a DebitAccount and a CreditAccount share the same Account base class.
@MappedSuperclass
public static class Account {

    @Id
    private Long id;

    private String owner;

    private BigDecimal balance;

    private BigDecimal interestRate;

    //Getters and setters are omitted for brevity

}

@Entity(name = "DebitAccount")
public static class DebitAccount extends Account {

    private BigDecimal overdraftFee;

    //Getters and setters are omitted for brevity

}

@Entity(name = "CreditAccount")
public static class CreditAccount extends Account {

    private BigDecimal creditLimit;

    //Getters and setters are omitted for brevity

}
CREATE TABLE DebitAccount (
    id BIGINT NOT NULL ,
    balance NUMERIC(19, 2) ,
    interestRate NUMERIC(19, 2) ,
    owner VARCHAR(255) ,
    overdraftFee NUMERIC(19, 2) ,
    PRIMARY KEY ( id )
)

CREATE TABLE CreditAccount (
    id BIGINT NOT NULL ,
    balance NUMERIC(19, 2) ,
    interestRate NUMERIC(19, 2) ,
    owner VARCHAR(255) ,
    creditLimit NUMERIC(19, 2) ,
    PRIMARY KEY ( id )
)

Hibernate/JPA MappedSuperclass Inheritance Step-By-Step Example

Let's demonstrate the usage of @MappedSuperclass annotation with a complete example.

Technologies and tools used

  • Hibernate 6.1.7.Final
  • IDE - Eclipse
  • Maven 3.5.3
  • Java 17
  • MySQL - 8.0.32

Development Steps

  1. Create a Simple Maven Project
  2. Project Directory Structure
  3. Add jar Dependencies to pom.xml
  4. Creating the JPA Entities
  5. Create a Hibernate configuration file - hibernate.cfg.xml
  6. Create a Hibernate utility class
  7. Create the Main class and Run an Application

1. Create a Simple Maven Project

Use the How to Create a Simple Maven Project in Eclipse article to create a simple Maven project in Eclipse IDE.

2. Project Directory Structure

The project directory structure for your reference - 

3. Add jar Dependencies to 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>
    <parent>
        <groupId>net.javaguides.hibernate</groupId>
        <artifactId>hibernate-tutorial</artifactId>
        <version>0.0.1-SNAPSHOT</version>
    </parent>
    <artifactId>hibernate-mappedsuperclass-example</artifactId>
    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
    </properties>
    <dependencies>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.32</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>6.1.7.Final</version>
        </dependency>
    </dependencies>
    <build>
        <sourceDirectory>src/main/java</sourceDirectory>
        <plugins>
            <plugin>
                <artifactId>maven-compiler-plugin</artifactId>
                <version>3.5.1</version>
                <configuration>
                    <source>17</source>
                    <target>17</target>
                </configuration>
            </plugin>
        </plugins>
    </build>
</project>

4. Creating the JPA Entities

Let's define the following Account base class:

Account.java

package net.javaguides.hibernate.entity;

import jakarta.persistence.*;

@MappedSuperclass
public abstract class Account {

    @Id
    @GeneratedValue(strategy = GenerationType.IDENTITY)
    private Long id;

    private String owner;

    private double balance;

    private double interestRate;

    public Long getId() {
        return id;
    }

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

    public String getOwner() {
        return owner;
    }

    public void setOwner(String owner) {
        this.owner = owner;
    }

    public double getBalance() {
        return balance;
    }

    public void setBalance(double balance) {
        this.balance = balance;
    }

    public double getInterestRate() {
        return interestRate;
    }

    public void setInterestRate(double interestRate) {
        this.interestRate = interestRate;
    }
}

CreditAccount.java

Let's create CreditAccount class that extends the Account base class:
package net.javaguides.hibernate.entity;

import jakarta.persistence.Entity;

@Entity(name = "CreditAccount")
public class CreditAccount extends Account {

    private double creditLimit;

    public double getCreditLimit() {
        return creditLimit;
    }

    public void setCreditLimit(double creditLimit) {
        this.creditLimit = creditLimit;
    }
}

DebitAccount.java

Let's create DebitAccount class that extends the Account base class:
package net.javaguides.hibernate.entity;

import jakarta.persistence.Entity;

@Entity(name = "DebitAccount")
public class DebitAccount extends Account {

    private double overdraftFee;

    public double getOverdraftFee() {
        return overdraftFee;
    }

    public void setOverdraftFee(double overdraftFee) {
        this.overdraftFee = overdraftFee;
    }
}

5. Create a Hibernate configuration file - hibernate.cfg.xml

Let's create an XML file named hibernate.cfg.xml under the resources folder and write the following code in it.
<!DOCTYPE hibernate-configuration PUBLIC
        "-//Hibernate/Hibernate Configuration DTD 3.0//EN"
        "http://www.hibernate.org/dtd/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
    <session-factory>
        <!-- JDBC Database connection settings -->
        <property name="connection.driver_class">com.mysql.cj.jdbc.Driver</property>
        <property name="connection.url">jdbc:mysql://localhost:3306/hibernate_db?useSSL=false</property>
        <property name="connection.username">root</property>
        <property name="connection.password">root</property>
        <!-- JDBC connection pool settings ... using built-in test pool -->
        <property name="connection.pool_size">1</property>
        <!-- Echo the SQL to stdout -->
        <property name="show_sql">true</property>
        <!-- Set the current session context -->
        <property name="current_session_context_class">thread</property>
        <!-- Drop and re-create the database schema on startup -->
        <property name="hbm2ddl.auto">create-drop</property>
        <!-- dbcp connection pool configuration -->
        <property name="hibernate.dbcp.initialSize">5</property>
        <property name="hibernate.dbcp.maxTotal">20</property>
        <property name="hibernate.dbcp.maxIdle">10</property>
        <property name="hibernate.dbcp.minIdle">5</property>
        <property name="hibernate.dbcp.maxWaitMillis">-1</property>
        <mapping class="net.javaguides.hibernate.entity.CreditAccount" />
 <mapping class="net.javaguides.hibernate.entity.DebitAccount" />
    </session-factory>
</hibernate-configuration>
The configuration file contains information about the database and mapping file. Conventionally, its name should be hibernate.cfg.xml.

6. Create a Hibernate Utility Class

Let's create a helper class to bootstrap hibernate SessionFactory:
package net.javaguides.hibernate.util;

import org.hibernate.SessionFactory;
import org.hibernate.boot.Metadata;
import org.hibernate.boot.MetadataSources;
import org.hibernate.boot.registry.StandardServiceRegistry;
import org.hibernate.boot.registry.StandardServiceRegistryBuilder;

public class HibernateUtil {
    private static StandardServiceRegistry registry;
    private static SessionFactory sessionFactory;

    public static SessionFactory getSessionFactory() {
        if (sessionFactory == null) {
            try {
                // Create registry
                registry = new StandardServiceRegistryBuilder().configure().build();

                // Create MetadataSources
                MetadataSources sources = new MetadataSources(registry);

                // Create Metadata
                Metadata metadata = sources.getMetadataBuilder().build();

                // Create SessionFactory
                sessionFactory = metadata.getSessionFactoryBuilder().build();

            } catch (Exception e) {
                e.printStackTrace();
                if (registry != null) {
                    StandardServiceRegistryBuilder.destroy(registry);
                }
            }
        }
        return sessionFactory;
    }

    public static void shutdown() {
        if (registry != null) {
            StandardServiceRegistryBuilder.destroy(registry);
        }
    }
}

7. Create the main App class and Run an Application

package net.javaguides.hibernate;

import org.hibernate.Session;
import org.hibernate.Transaction;

import net.javaguides.hibernate.entity.CreditAccount;
import net.javaguides.hibernate.util.HibernateUtil;

public class App {
    public static void main(String[] args) {
        CreditAccount account = new CreditAccount();
        account.setBalance(10000.0);
        account.setInterestRate(10.0);
        account.setOwner("Ramesh");
        account.setCreditLimit(10000.0);

        Transaction transaction = null;
        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            // start a transaction
            transaction = session.beginTransaction();
            // save the account object
            session.persist(account);
            // commit transaction
            transaction.commit();
        }

        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            // start a transaction
            Transaction transaction1 = session.beginTransaction();
            // get the account object
            CreditAccount creditAccount = session.get(CreditAccount.class, 1 L);
            System.out.println(creditAccount.getBalance());
            System.out.println(creditAccount.getId());
            // commit transaction
            transaction1.commit();
        }
    }
}

Output



GitHub Repository

The complete source code of this article is available on my GitHub Repository - https://github.com/RameshMF/Hibernate-ORM-Tutorials

Conclusion

As we have seen JPA/Hibernate supports 4 inheritance strategies that map the domain objects to different table structures. In this article, we have discussed the first mapped superclass strategy, which is the simplest approach to mapping an inheritance structure to database tables. It maps each concrete class to its own table. 
Check out below remaining inheritance strategies articles: 
You can learn more about Hibernate ORM Framework at Hibernate Tutorial

Comments