Hibernate/JPA MappedSuperclass Inheritance Example

JPA/Hibernate support 4 inheritance strategies which map the domain objects to different table structures. In this article, we will discuss 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.
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 )
)
Let's demonstrates the usage of @MappedSuperclass Annotation with a complete example.

Technologies and tools used

  • Hibernate 5.3.7.Final
  • IDE - Eclipse Noen
  • Maven 3.5.3
  • JavaSE 1.8
  • MySQL - 8.0.13

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 How to Create a Simple Maven Project in Eclipse article to create 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.13</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
        <dependency>
            <groupId>org.hibernate</groupId>
            <artifactId>hibernate-core</artifactId>
            <version>5.3.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>1.8</source>
                    <target>1.8</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 javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;

@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

package net.javaguides.hibernate.entity;

import javax.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

package net.javaguides.hibernate.entity;

import javax.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

The configuration file contains information about the database and mapping file. Conventionally, its name should be hibernate.cfg.xml .
Let's create an XML file named as hibernate.cfg.xml under 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>
        <!-- Select our SQL dialect -->
        <property name="dialect">org.hibernate.dialect.MySQL5Dialect</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>

6. Create a Hibernate utility Class

Create a helper class to bootstrap hibernate SessionFactory. In most Hibernate applications, the SessionFactory should be instantiated once during application initialization. The single instance should then be used by all code in a particular process, and any Session should be created using this single SessionFactory. The SessionFactory is thread-safe and can be shared; a Session is a single-threaded object.
The bootstrapping API is quite flexible, but in most cases, it makes the most sense to think of it as a 3 step process:
  1. Build the StandardServiceRegistry
  2. Build the Metadata
  3. Use those 2 to build the 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.save(account);
            // commit transaction
            transaction.commit();
        }

        try (Session session = HibernateUtil.getSessionFactory().openSession()) {
            // start a transaction
            Transaction transaction1 = session.beginTransaction();
            // save 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 available on my GitHub Repository - https://github.com/RameshMF/Hibernate-ORM-Tutorials

Conclusion

As we have seen JPA/Hibernate supports 4 inheritance strategies which 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

References

Comments