Blog Image

Table Per Concrete Class Using Annotation  

In this blog, we show you how to use Hibernate to implement "Inheritance Mapping Table Per Concrete Class Hierarchy relationship by using jpa Annotation approach. This is the most common use case we often encounter in an Application Development.

Below is the example for Inheritance Mapping Table Per Concrete Class Hierarchy Annotation approach.

Lets see Inheritance Mapping example:
Technologies used :-
1) java (1.8).
2) maven (3.5.2).
3) hibernate (5.2.12).
4) MySql (5.7.21).

Below is the table structure
Execute this query for creating tables in Database(MySql).
CREATE TABLE `savings_account` (
  `account_no` int(11) NOT NULL,
  `account_holder_nm` varchar(255) DEFAULT NULL,
  `amount` float DEFAULT NULL,
  `open_dt` datetime DEFAULT NULL,
  `has_cheque_book_facility` bit(1) DEFAULT NULL,
  `max_withdrawl` float DEFAULT NULL,
  `min_balance` float DEFAULT NULL,
  PRIMARY KEY (`account_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

CREATE TABLE `account` (
  `account_no` int(11) NOT NULL,
  `account_holder_nm` varchar(255) DEFAULT NULL,
  `amount` float DEFAULT NULL,
  `open_dt` datetime DEFAULT NULL,
  PRIMARY KEY (`account_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

CREATE TABLE `current_account` (
  `account_no` int(11) NOT NULL,
  `account_holder_nm` varchar(255) DEFAULT NULL,
  `amount` float DEFAULT NULL,
  `open_dt` datetime DEFAULT NULL,
  `company_nm` varchar(255) DEFAULT NULL,
  `over_draft_limit` float DEFAULT NULL,
  PRIMARY KEY (`account_no`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8$$

Project Structure

Below is the maven project structure with packages and java/resource files.
Entity Classes
Account.java
package com.tpcc.entities;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.Inheritance;
import javax.persistence.InheritanceType;
import javax.persistence.Table;

import org.hibernate.annotations.GenericGenerator;

@SuppressWarnings("serial")
@Entity
@Table(name = "account")
@Inheritance(strategy = InheritanceType.TABLE_PER_CLASS)
public class Account implements Serializable {
    @Id
    @Column(name = "account_no")
    @GeneratedValue(generator = "incr_gen")
    @GenericGenerator(name = "incr_gen", strategy = "increment")
    protected int accountNO;
    @Column(name = "account_holder_nm")
    protected String accountHolderName;
    @Column(name = "open_dt")
    protected Date openDate;
    @Column(name = "amount")
    protected float amount;

    public int getAccountNO() {
        return accountNO;
    }

    public void setAccountNO(int accountNO) {
        this.accountNO = accountNO;
    }

    public String getAccountHolderName() {
        return accountHolderName;
    }

    public void setAccountHolderName(String accountHolderName) {
        this.accountHolderName = accountHolderName;
    }

    public Date getOpenDate() {
        return openDate;
    }

    public void setOpenDate(Date openDate) {
        this.openDate = openDate;
    }

    public float getAmount() {
        return amount;
    }

    public void setAmount(float amount) {
        this.amount = amount;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result + ((accountHolderName == null) ? 0 : accountHolderName.hashCode());
        result = prime * result + accountNO;
        result = prime * result + Float.floatToIntBits(amount);
        result = prime * result + ((openDate == null) ? 0 : openDate.hashCode());
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        Account other = (Account) obj;
        if (accountHolderName == null) {
            if (other.accountHolderName != null)
                return false;
        } else if (!accountHolderName.equals(other.accountHolderName))
            return false;
        if (accountNO != other.accountNO)
            return false;
        if (Float.floatToIntBits(amount) != Float.floatToIntBits(other.amount))
            return false;
        if (openDate == null) {
            if (other.openDate != null)
                return false;
        } else if (!openDate.equals(other.openDate))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "Account [accountNO=" + accountNO + ", accountHolderName=" + accountHolderName + ", openDate=" + openDate
                + ", amount=" + amount + "]";
    }
}
CurrentAccount.java
package com.tpcc.entities;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@SuppressWarnings("serial")
@Entity
@Table(name = "current_account")
@AttributeOverrides({ @AttributeOverride(name = "account_no", column = @Column(name = "current_account_no")) })
public class CurrentAccount extends Account {
    @Column(name = "over_draft_limit")
    protected float overDraftLimit;
    @Column(name = "company_nm")
    protected String companyName;

    public float getOverDraftLimit() {
        return overDraftLimit;
    }

    public void setOverDraftLimit(float overDraftLimit) {
        this.overDraftLimit = overDraftLimit;
    }

    public String getCompanyName() {
        return companyName;
    }

    public void setCompanyName(String companyName) {
        this.companyName = companyName;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + ((companyName == null) ? 0 : companyName.hashCode());
        result = prime * result + Float.floatToIntBits(overDraftLimit);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (getClass() != obj.getClass())
            return false;
        CurrentAccount other = (CurrentAccount) obj;
        if (companyName == null) {
            if (other.companyName != null)
                return false;
        } else if (!companyName.equals(other.companyName))
            return false;
        if (Float.floatToIntBits(overDraftLimit) != Float.floatToIntBits(other.overDraftLimit))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "CurrentAccount [overDraftLimit=" + overDraftLimit + ", companyName=" + companyName + ", accountNO="
                + accountNO + ", accountHolderName=" + accountHolderName + ", openDate=" + openDate + ", amount="
                + amount + "]";
    }

}
SavingsAccount.java
package com.tpcc.entities;

import javax.persistence.AttributeOverride;
import javax.persistence.AttributeOverrides;
import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.Table;

@SuppressWarnings("serial")
@Entity
@Table(name = "savings_account")
@AttributeOverrides({ @AttributeOverride(name = "account_no", column = @Column(name = "saving_account_no")) })
public class SavingsAccount extends Account {
    @Column(name = "min_balance")
    protected float minBalance;
    @Column(name = "has_cheque_book_facility")
    protected boolean hasChequeBookFacility;
    @Column(name = "max_withdrawl")
    protected float maxWithdrawl;

    public float getMinBalance() {
        return minBalance;
    }

    public void setMinBalance(float minBalance) {
        this.minBalance = minBalance;
    }

    public boolean isHasChequeBookFacility() {
        return hasChequeBookFacility;
    }

    public void setHasChequeBookFacility(boolean hasChequeBookFacility) {
        this.hasChequeBookFacility = hasChequeBookFacility;
    }

    public float getMaxWithdrawl() {
        return maxWithdrawl;
    }

    public void setMaxWithdrawl(float maxWithdrawl) {
        this.maxWithdrawl = maxWithdrawl;
    }

    @Override
    public int hashCode() {
        final int prime = 31;
        int result = super.hashCode();
        result = prime * result + (hasChequeBookFacility ? 1231 : 1237);
        result = prime * result + Float.floatToIntBits(maxWithdrawl);
        result = prime * result + Float.floatToIntBits(minBalance);
        return result;
    }

    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (!super.equals(obj))
            return false;
        if (getClass() != obj.getClass())
            return false;
        SavingsAccount other = (SavingsAccount) obj;
        if (hasChequeBookFacility != other.hasChequeBookFacility)
            return false;
        if (Float.floatToIntBits(maxWithdrawl) != Float.floatToIntBits(other.maxWithdrawl))
            return false;
        if (Float.floatToIntBits(minBalance) != Float.floatToIntBits(other.minBalance))
            return false;
        return true;
    }

    @Override
    public String toString() {
        return "SavingsAccount [minBalance=" + minBalance + ", hasChequeBookFacility=" + hasChequeBookFacility
                + ", maxWithdrawl=" + maxWithdrawl + ", accountNO=" + accountNO + ", accountHolderName="
                + accountHolderName + ", openDate=" + openDate + ", amount=" + amount + "]";
    }
}
SessionFactoryRegistry.java
package com.tpcc.util;

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

public class SessionFactoryRegistry {
    private static SessionFactory sessionFactory;

    static {
        sessionFactory= new MetadataSources(new StandardServiceRegistryBuilder().configure().build())
                .getMetadataBuilder().build().buildSessionFactory();
    }
   
    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void closeSessionFactory() {
        if (sessionFactory != null) {
            sessionFactory.close();
            sessionFactory=null;
        }
    }  
}
hibernate.cfg.xml
<?xml version="1.0" encoding="UTF-8"?>
<!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>
        <property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
        <property name="hibernate.connection.password">welcome1</property>
        <property name="hibernate.connection.url">jdbc:mysql://localhost:3306/inheritance_mapping</property>
        <property name="hibernate.connection.username">root</property>
        <property name="hibernate.dialect">org.hibernate.dialect.MySQL5InnoDBDialect</property>
        <property name="hibernate.hbm2ddl.auto">update</property>
        <property name="show_sql">true</property>
        <property name="format_sql">true</property>
        <property name="current_session_context_class">thread</property>
                       
        <mapping class="com.tpcc.entities.Account"/>
        <mapping class="com.tpcc.entities.SavingsAccount"/>
        <mapping class="com.tpcc.entities.CurrentAccount"/>
    </session-factory>
</hibernate-configuration>
pom.xml
<?xml version="1.0" encoding="UTF-8"?>

<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.otm.configure</groupId>
  <artifactId>Table-Per-Concrete-Class-Annotation</artifactId>
  <version>1.0-SNAPSHOT</version>

  <name>Table-Per-Concrete-Class-Annotation</name>
  <!-- FIXME change it to the project's website -->
  <url>http://www.example.com</url>;

  <properties>
        <maven-compiler-plugin.version>3.2</maven-compiler-plugin.version>
        <javaee-api.version>6.0</javaee-api.version>
        <javax.servlet.version>3.1.0</javax.servlet.version>
    </properties>

  <dependencies>
        <dependency>
              <groupId>org.hibernate</groupId>
              <artifactId>hibernate-core</artifactId>
              <version>5.2.12.Final</version>
        </dependency>
        <dependency>
              <groupId>mysql</groupId>
              <artifactId>mysql-connector-java</artifactId>
              <version>5.1.34</version>
        </dependency>    
  </dependencies>

  <build>
    <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
      <plugins>
        <plugin>
          <artifactId>maven-clean-plugin</artifactId>
          <version>3.0.0</version>
        </plugin>
        <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_jar_packagi... -->
        <plugin>
          <artifactId>maven-resources-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-compiler-plugin</artifactId>
          <version>3.7.0</version>
        </plugin>
        <plugin>
          <artifactId>maven-surefire-plugin</artifactId>
          <version>2.20.1</version>
        </plugin>
        <plugin>
          <artifactId>maven-jar-plugin</artifactId>
          <version>3.0.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-install-plugin</artifactId>
          <version>2.5.2</version>
        </plugin>
        <plugin>
          <artifactId>maven-deploy-plugin</artifactId>
          <version>2.8.2</version>
        </plugin>
      </plugins>
    </pluginManagement>
  </build>
</project>
Test.java
package com.tpcc.test;

import java.util.Date;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import com.tpcc.entities.Account;
import com.tpcc.entities.CurrentAccount;
import com.tpcc.entities.SavingsAccount;
import com.tpcc.util.SessionFactoryRegistry;

public class Test {
    public static void main(String[] args) {
        SessionFactory sessionFactory = null;
        Session session = null;
        Transaction transaction = null;
        boolean flag = false;

        Account account = null;
        SavingsAccount savingsAccount = null;
        CurrentAccount currentAccount = null;

        try {
            sessionFactory = SessionFactoryRegistry.getSessionFactory();
            session = sessionFactory.openSession();
            transaction = session.beginTransaction();

            account = new Account();
            account.setAccountHolderName("Rahul");
            account.setOpenDate(new Date());
            account.setAmount(1000);
            session.save(account);

            savingsAccount = new SavingsAccount();
            savingsAccount.setAccountHolderName("Sam");
            savingsAccount.setOpenDate(new Date());
            savingsAccount.setAmount(2000);
            savingsAccount.setMinBalance(2000);
            savingsAccount.setHasChequeBookFacility(true);
            savingsAccount.setMaxWithdrawl(20000);
            session.save(savingsAccount);

            currentAccount = new CurrentAccount();
            currentAccount.setAccountHolderName("Susan");
            currentAccount.setOpenDate(new Date());
            currentAccount.setAmount(5000);
            currentAccount.setOverDraftLimit(4000);
            currentAccount.setCompanyName("dell");
            session.save(currentAccount);

            account = session.get(Account.class, 1);
            System.out.println(account);

            savingsAccount = session.get(SavingsAccount.class, 2);
            System.out.println(savingsAccount);

            currentAccount = session.get(CurrentAccount.class, 3);
            System.out.println(currentAccount);

            flag = true;
        } finally {
            if (transaction != null) {
                if (flag) {
                    transaction.commit();
                } else {
                    transaction.rollback();
                }
            }
            if (session != null) {
                session.close();
            }
            SessionFactoryRegistry.closeSessionFactory();
        }
    }
}


Please find attached the Table_Per_Concrete_Class_Annotation.zip as an maven project as a reference. Feel free to pass your comments in the blog.

About author

User Image
Sriman

A software developer on JDK and JEE platform. I am passionate about Java technology and always an explorer and learner in new technologies in Java. I have experience on Open Source technologies like Struts, Spring, Jsf etc.. and even strong knowledge on Integration/Distributed world like Ejb, Web Services and Restful Services.

3

-Comments

Be the first person to write a comment for this Blog
  • author image
    by:
      rajeev4600
      13-10-2018 09:05:33 PM

    i want to download spring 3.0 jars source code.please suggest from whhere i can download?

  • author image
    by:
      Adriantoth
      03-9-2018 10:35:57 AM

    Great material! This is really a good article because you always post grand related content and very informative information with powerful points. https://rospher.com/

  • author image
    by:
      prabina kumar
      14-7-2018 10:50:48 PM

    Thanks, its very good information,clear and clarity came while reading this blogs,thanks for your information.

Load More

No More Comments

Leave a Comment

Your comment has been posted and will appear soon.