21 - Hibernate Annotations

21.1 Overview

We can configure the metadata in entity class itself using annotation instead of configuring in hbm files. One of the biggest advantages of using annotations over hbm files is that we can get rid of hbm files. There   can be scenarios where you might need hbm files even if you are  using annotations.

Annotations are JPA2 specification compliant and will be available under javax.persistence.* package. Hibernate also provides annotations with the same name under org.hibernate.annotation package but those are the extension over JPA. My recommendation is to use JAP annotations as much as possible so that application code remains portable.

21.2 Annotations Details

  1. @Entity – this annotation is used at a class level to define that this class is an entity so the class must follow all the entity rules.
  2. @Table- this annotation is also used at a class level and is used to provide the table name to which the entity will be mapped. We need to use name attribute of @Table annotation to supply the table name.
  3. @Id – This annotation is applied on a column and it has a special meaning. This informs hibernate that corresponding property will be used as an entity identifier. It is equivalent to use of <id> tag in hbm files.
  4. @GeneratedValue – Hibernate automatically uses the id generation strategy when we add @Id annotation. However to override the ID generation strategy we can use @GeneratedValue annotation with @Id. This annotation accepts two attributes strategy  and generator.
  5. @Column- this annotation is applied on a property and is used to map the property with table column. @Column annotation exposes following commonly used  attributes-
  • name- to specify the name of column
  • length- to specify the length of column
  • nullable- to apply not-null constraint
  • unique- to apply unique constraint
  • insertable- is equivalent to insert=false/true which decide to use this column in insert or not when the value is null
  • updatable - is equivalent to update=false/true which decide to use this column in update or not when the value is null
  1. @Version – this annotation is applied on column and specifies that this column will be used for versioning.
  2. @Transient- By default all non-static properties are considered as persistent so to ignore any particular property from persistent, add @Transient annotation. If we do not mark field with @Column then also property will be considered as persistent and it will be mapped with the column of same name as property name. Hibernate assumes those fields to be annotated as @Basic.

 

Below is the detail of Associations Annotations

  1. @OneToMany – this annotation is applied on a collection property to manage one to many relationship. Use mappedBy attribute for bidirectional associations.

        For a unidirectional association with join column approach , we need to use @JoinColumn annotation in conjunction with @OneToMany annotation

  1. @ManyToOne- this annotation is used to manage one to many relationship with @JoinColumn to specify the join column in entities.
  2. @ManyToMany – this annotation is used to manage many to many relationship with @JoinTable annotation to specify the join table.
  3. @OneToOne- this annotation is used to manage one to one relationship with @JoinColumn annotation to specify foreign key- primary  key relationship

 

21.3 Specify accessor Strategy

Depending on the location where the annotation is added, it decides the accessor strategy. Applying annotation on field enables field accessor and applying it on getter makes it a property accessor.

21.4 Configurations

In traditional xml approach we use <mapping resource> tag to specify the mapping files but in case of annotation,we can use one of the approaches

  1. Use <mapping class> tag to map the entity class
  2. Load entity class using addAnnotatedClass() method of AnnotationConfiguration like below

factory = new AnnotationConfiguration().

21.5 Examples

21.5.1 Basic Entity Persistence

Lets take an example of Book Entity.

a. Hibernate.cfg.xml file 

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
    "-//Hibernate/Hibernate Configuration DTD//EN"
    "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>

    <session-factory>

        <property name="hibernate.connection.url">
            jdbc:mysql://localhost:3306/tutorial
        </property>
        <property name="hibernate.connection.username">
            root
        </property>
        <property name="hibernate.connection.password">
            password
        </property>
        <property name="dialect">org.hibernate.dialect.MySQLDialect</property>

        <property name="hibernate.format_sql">true</property>        
        <property name="show_sql">true</property>  

        <property name="hibernate.connection.driver_class">
            com.mysql.jdbc.Driver
        </property>

        <mapping class ="com.tutorial.hibernate.Book" />
    </session-factory>
</hibernate-configuration>

b. Book.java

package com.tutorial.hibernate;

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

@Entity
@Table(name="Book")
public class Book {

     @Id
     @GeneratedValue
     @Column(name="book_id")
     private int isbn;

     @Column(name="name")
     private String name;

     @Column(name="author")
     private String author;

     public int getIsbn() {
        return isbn;
    }
    public void setIsbn(int isbn) {
        this.isbn = isbn;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getAuthor() {
        return author;
    }
    public void setAuthor(String author) {
        this.author = author;
    }
}

c. Create Book Table script

create table Book (
        book_id integer not null auto_increment,
        author varchar(255),
        name varchar(255),
        primary key (book_id)

d. Test Program- One thing to note here is we need to use AnnotationConfiguration class 

import com.tutorial.hibernate.Book;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

public class Test {
 
    private static SessionFactory factory;
    public static void main(String args[])
    {
      Configuration cfg = new AnnotationConfiguration().configure();

      factory = cfg.buildSessionFactory();
      Session session = factory.openSession();        
      Transaction tx = session.beginTransaction();
 
      Book book = new Book();
      book.setAuthor("author 1 ");
      book.setName("book name ");

      session.save(book);

      session.flush();
      tx.commit();

      session.close();        
        factory.close();
    }    
}

e. Running the program will end up in below state of Book Table

 

21.5.2  One to Many Example

Lets take an example of File and Folder relationship (One Folder can have many Files ) for One to many associations.

  1. Add mappings for File and Folder entities in hibernate.cfg.xml file as below 

       <mapping class ="com.tutorial.hibernate.File" />

        <mapping class ="com.tutorial.hibernate.Folder" />

 b.  Create File and Folder Tables 

create table file (
        file_id integer not null auto_increment,
        file_extension varchar(255),
        file_name varchar(255),
        file_size integer,
        folder_id integer,
        primary key (file_id)
    )

create table folder (
        folder_id integer not null auto_increment,
        folder_name varchar(255),
        primary key (folder_id)
    )

c. File entity 

package com.tutorial.hibernate;

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

@Entity
@Table(name="file")
public class File{

    private int fileId;    
    private String name;    
    private int size;    
    private String extension;

    @Id
    @GeneratedValue
    @Column(name="file_id")
    public int getFileId() {
        return fileId;
    }
    public void setFileId(int fileId) {
        this.fileId = fileId;
    }

    @Column(name="file_name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    
    @Column(name="file_size")
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }

    @Column(name="file_extension")
    public String getExtension() {
        return extension;
    }
    public void setExtension(String extension) {
        this.extension = extension;
    }   
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((extension == null) ? 0 : extension.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + size;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        File other = (File) obj;
        if (extension == null) {
            if (other.extension != null)
                return false;
        } else if (!extension.equals(other.extension))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (size != other.size)
            return false;
        return true;
    }    
}

d. Folder entity

package com.tutorial.hibernate;

import java.util.HashSet;
import java.util.Set;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.OneToMany;
import javax.persistence.Table;

@Entity
@Table(name="folder")
public class Folder {

    private int folderId;    
    private String folderName;    
    private Set<File> files = new HashSet<File>();
    
    @Id
    @GeneratedValue
    @Column(name="folder_id")
    public int getFolderId() {
        return folderId;
    }

    public void setFolderId(int folderId) {
        this.folderId = folderId;
    }
    @Column(name="folder_name")
    public String getFolderName() {
        return folderName;
    }
    public void setFolderName(String folderName) {
        this.folderName = folderName;
    }
    @OneToMany
    @JoinColumn(name="folder_id")
    public Set<File> getFiles() {
        return files;
    }
    public void setFiles(Set<File> files) {
        this.files = files;
    }
}

e. Test Program 

import com.tutorial.hibernate.File;
import com.tutorial.hibernate.Folder;

import java.util.HashSet;
import java.util.Set;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

public class Test {

     private static SessionFactory factory;
     public static void main(String args[])
     {
        Configuration cfg = new AnnotationConfiguration().configure();
        factory = cfg.buildSessionFactory();
        Session session = factory.openSession();        
        Transaction tx = session.beginTransaction();

        File f1 = new File();
        f1.setExtension(".xls");
        f1.setName("Excel File");
        f1.setSize(1024);

        File f2 = new File();
        f2.setExtension(".doc");
        f2.setName("Word File");
        f2.setSize(2048);

        Set<File> files = new HashSet<File>();
        files.add(f2);
        files.add(f1);

        session.save(f1);
        session.save(f2);

        Folder folder = new Folder();
        folder.setFolderName("Documents");
        folder.setFiles(files);  

        session.save(folder);
        session.flush();
        tx.commit();

        session.close();        
        factory.close();
    }    
}

f. Database state after running test program 

 

 

21.5.3   Many to One Example

Let's take an example of File and Folder relationship (Many files will reside under One Folder) for  many to one  association.

  1. Add mappings for File and Folder entities in hibernate.cfg.xml file as below 

             <mapping class ="com.tutorial.hibernate.File" />

<mapping class ="com.tutorial.hibernate.Folder" />

 b.  Create File and Folder Tables 

create table file (
        file_id integer not null auto_increment,
        file_extension varchar(255),
        file_name varchar(255),
        file_size integer,
        folder_id integer,
        primary key (file_id)
    )

create table folder (
        folder_id integer not null auto_increment,
        folder_name varchar(255),
        primary key (folder_id)
    )

c. File entity 

package com.tutorial.hibernate;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.JoinColumn;
import javax.persistence.ManyToOne;
import javax.persistence.Table;

@Entity
@Table(name="file")
public class File{

    private int fileId;    
    private String name;    
    private int size;    
    private String extension;    
    private Folder folder;

    @Id
    @GeneratedValue
    @Column(name="file_id")
    public int getFileId() {
        return fileId;
    }
    public void setFileId(int fileId) {
        this.fileId = fileId;
    }    
    @Column(name="file_name")
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }    
    @Column(name="file_size")
    public int getSize() {
        return size;
    }
    public void setSize(int size) {
        this.size = size;
    }    
    @Column(name="file_extension")
    public String getExtension() {
        return extension;
    }
    public void setExtension(String extension) {
        this.extension = extension;
    }    
    @ManyToOne
    @JoinColumn(name="folder_id")
    public Folder getFolder() {
        return folder;
    }
    public void setFolder(Folder folder) {
        this.folder = folder;
    }
    @Override
    public int hashCode() {
        final int prime = 31;
        int result = 1;
        result = prime * result
                + ((extension == null) ? 0 : extension.hashCode());
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        result = prime * result + size;
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        File other = (File) obj;
        if (extension == null) {
            if (other.extension != null)
                return false;
        } else if (!extension.equals(other.extension))
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        if (size != other.size)
            return false;
        return true;
    }    
}

d. Folder entity 

package com.tutorial.hibernate;

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

@Entity
@Table(name="folder")
public class Folder {

       private int folderId;    
       private String folderName; 

       @Id
       @GeneratedValue
       @Column(name="folder_id")
       public int getFolderId() {
          return folderId;
       }
       public void setFolderId(int folderId) {
          this.folderId = folderId;
       }
       @Column(name="folder_name")
       public String getFolderName() {
          return folderName;
       }
       public void setFolderName(String folderName) {
           this.folderName = folderName;
       }
}

e. Test Program

import com.tutorial.hibernate.File;
import com.tutorial.hibernate.Folder;

import org.hibernate.Session;
import org.hibernate.SessionFactory;
import org.hibernate.Transaction;
import org.hibernate.cfg.AnnotationConfiguration;
import org.hibernate.cfg.Configuration;

public class Test {

       private static SessionFactory factory;
       public static void main(String args[])
       {
           Configuration cfg = new AnnotationConfiguration().configure();
           factory = cfg.buildSessionFactory();
           Session session = factory.openSession();        
           Transaction tx = session.beginTransaction();

           File f1 = new File();
           f1.setExtension(".xls");
           f1.setName("Excel File");
           f1.setSize(1024);

           File f2 = new File();
           f2.setExtension(".doc");
           f2.setName("Word File");
           f2.setSize(2048);

           Folder folder = new Folder();
           folder.setFolderName("Documents");

           f1.setFolder(folder);
           f2.setFolder(folder);
  
           session.save(f1);
           session.save(f2);

           session.save(folder);
           session.flush();
           tx.commit();

           session.close();        
          factory.close();
    }    
}

f. Database state after running test program

   

Like us on Facebook