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
- Create a Simple Maven Project
- Project Directory Structure
- Add jar Dependencies to pom.xml
- Creating the JPA Entities
- Create a Hibernate configuration file - hibernate.cfg.xml
- Create a Hibernate utility class
- 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.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>
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:
- Hibernate/JPA MappedSuperclass Inheritance Example
- Hibernate/JPA Single Table Inheritance Example
- Hibernate JPA Joined Table Inheritance Example
You can learn more about Hibernate ORM Framework at Hibernate Tutorial
Comments
Post a Comment
Leave Comment