Monday, August 29, 2011

MULE HTTP Web Service - Step2A. Creating the client jars from the WSDL with Options

This step focuses on creating the client jars from the WSDL created in the previous step. This serves two purposes.
  1. To verify that the WSDL and the XSD was created without any errors.
  2. To get the jars ready so that we will have the class files generated for the objects defined in XSD. These classes will be used in our Mule web service.
This example focuses on using the Maven cxf-codegen-plugin to generate the classes.

Since we are going to develop a Mule Web Service using maven, we can easily import the client jar in your pom.xml

1. Create a simple maven project in Eclipse.



2. Add the cxf-codegen-plugin to your 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>
    <groupId>org.hello</groupId>
    <artifactId>HelloServiceClient</artifactId>
    <version>1.0-SNAPSHOT</version>
    <packaging>jar</packaging>
    <build>
        <plugins>
            <plugin>
                <groupId>org.apache.cxf</groupId>
                <artifactId>cxf-codegen-plugin</artifactId>
                <version>2.4.0</version>
                <executions>
                    <execution>
                        <id>generate-sources</id>
                        <phase>generate-sources</phase>
                        <configuration>
                            <sourceRoot>${project.build.directory}/generated/cxf</sourceRoot>
                            <wsdlOptions>
                                <wsdlOption>
                                    <extraargs>
                                        <extraarg>-p</extraarg>
                                        <extraarg>http://hello.services.com=com.services.hello.helloservice</extraarg>
                                        <extraarg>-p</extraarg>
                                        <extraarg>http://ws.hello.services.com=com.services.hello.helloservice.ws</extraarg>
                                    </extraargs>
                                    <wsdl>${basedir}/src/main/resources/Hello.wsdl</wsdl>
                                    <bindingFiles>
                                        <bindingFile>${basedir}/src/main/resources/bindings.xml</bindingFile>
                                    </bindingFiles>
                                </wsdlOption>
                            </wsdlOptions>
                        </configuration>
                        <goals>
                            <goal>wsdl2java</goal>
                        </goals>
                    </execution>
                </executions>
            </plugin>
        </plugins>
    </build>
</project>

3. Move the WSDL and XSD created in the previous section under src/main/resources

4. Make sure that you have JDK in your project classpath and not JRE. This plugin needs to compile and generate the class files and it requires a JDK to do it.

5. Right click on the project, go to Run As and select Maven Package.

With the above steps the client jar would get generated successfully and the client jar should contain the following structure.


Sunday, August 14, 2011

HIBERNATE - Bidirectional Many-to-Many Association

In the following example, we will be going through the bidirectional Many-to-Many association using Hibernate. We will be using the Student and Professor table where a student will have one or more professors. The same professor will have one or more students.

Schema Creation:

Since many-to-many is not allowed on the database level (Normalization), we will change this to add a junction-entity table in the middle. I am using the name of the junction-entity table to have the combination of both the tables.

The entities will be translated as follows:

STUDENT STUDPROF PROFESSOR
ID SIDID
NAME PIDNAME
PHNO
PHNO
ADDRESS
DOB

CREATE TABLE STUDENT (
	ID INTEGER(5) PRIMARY KEY DEFAULT 1,
	NAME VARCHAR(30) NOT NULL,
	ADDRESS VARCHAR(30) NOT NULL,
	PHNO VARCHAR(10) NOT NULL
);

CREATE TABLE PROFESSOR (
	ID INTEGER(5) PRIMARY KEY DEFAULT 1,
	NAME VARCHAR(30) NOT NULL,
	PHNO VARCHAR(30) NOT NULL,
	DOB DATE NOT NULL
);

CREATE TABLE STUDPROF (
	SID INTEGER(5) NOT NULL DEFAULT 1,
	PID INTEGER(5) NOT NULL DEFAULT 1,
	PRIMARY KEY(SID, PID),
	FOREIGN KEY (SID) REFERENCES STUDENT (ID),
	FOREIGN KEY (PID) REFERENCES PROFESSOR (ID)
);

HBM Files Creation:

Professor.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
    <class name="Professor" table="PROFESSOR">
        <id name="id" column="ID" type="integer">
            <generator class="increment"></generator>
        </id>

        <property name="name" column="NAME" type="string"></property>

        <property name="phNo" column="PHNO" type="string"></property>

        <property name="dob" column="DOB" type="date"></property>

        <set name="students" table="STUDPROF" cascade="all" lazy="false">
            <key column="PID"></key>
            <many-to-many column="SID" class="Student"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

Student.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
    <class name="Student" table="STUDENT">
        <id name="id" column="ID">
            <generator class="increment"></generator>
        </id>

        <property name="name" column="NAME" type="string"
            update="false"></property>

        <property name="address" column="ADDRESS" type="string"
            update="false"></property>

        <property name="phNo" column="PHNO" type="string"
            update="false"></property>

        <set name="professors" table="STUDPROF" cascade="all" lazy="false">
            <key column="SID"></key>
            <many-to-many column="PID" class="Professor"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

Java Files:

Professor.java:

package org.mybusiness.pojos;

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

public class Professor implements Serializable {

    private static final long serialVersionUID = 2286787316913029844L;

    private int id;
    private String name;
    private String phNo;
    private Date dob;

    private Set<Student> students;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhNo() {
        return phNo;
    }

    public void setPhNo(String phNo) {
        this.phNo = phNo;
    }

    public Date getDob() {
        return dob;
    }

    public void setDob(Date dob) {
        this.dob = dob;
    }

    public Set<Student> getStudents() {
        return students;
    }

    public void setStudents(Set<Student> students) {
        this.students = students;
    }
}

Student.java:


package org.mybusiness.pojos;

import java.util.Set;

public class Student {

    private int id;
    private String name;
    private String address;
    private String phNo;

    private Set<Professor> professors;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhNo() {
        return phNo;
    }

    public void setPhNo(String phNo) {
        this.phNo = phNo;
    }

    public Set<Professor> getProfessors() {
        return professors;
    }

    public void setProfessors(Set<Professor> professors) {
        this.professors = professors;
    }
}

Functionalities:

Create Student and Professor:

public void createProfessorStudent() {

    Professor professor = new Professor();

    professor.setName("Gautham");
    professor.setPhNo("3144143141");
    professor.setDob(new Date());

    Set<Student> students = new HashSet<Student>();

    Student student = new Student();
    student.setId(5);

    students.add(student);

    student = new Student();
    student.setName("Johny");
    student.setAddress("Santa Clara");
    student.setPhNo("3144443141");

    students.add(student);
    professor.setStudents(students);

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);
    Session session = ht.getSessionFactory().openSession();
    Transaction tx = session.beginTransaction();

    try {

        session.saveOrUpdate(professor);
        tx.commit();
    } catch (Exception e) {
        e.printStackTrace();
        tx.rollback();
    } finally {
        session.close();
    }
}

Retrieve Student with Professor:

public void getProfessorStudent() {

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);
    DetachedCriteria criteria = DetachedCriteria.forClass(Professor.class,
            "prof");
    criteria.add(Restrictions.eq("prof.id", 4));

    List<Professor> professors = ht.findByCriteria(criteria);
    for (Professor prof : professors) {

        System.out.println("PROFESSOR: " + prof.getName() + ":"
                + prof.getPhNo() + ":" + prof.getDob());
        for (Student stud : prof.getStudents()) {
            System.out.println("STUDENT: " + stud.getName() + ":"
                    + stud.getPhNo());
        }
    }
}

Friday, August 12, 2011

HIBERNATE - Unidirectional Many-to-Many Association

In the following example, we will be going through the unidirectional Many-to-Many association using Hibernate. We will be using the Student and Professor table where a student will have one or more professors. The same professor will have lots of students.

Schema Creation:

Since many-to-many is not allowed on the database level (Normalization), we will change this to add a junction-entity table in the middle. I am using the name of the junction-entity table to have the combination of both the tables.

The entities will be translated as follows:

STUDENT STUDPROF PROFESSOR
ID SIDID
NAME PIDNAME
PHNO
PHNO
ADDRESS
DOB

CREATE TABLE STUDENT (
	ID INTEGER(5) PRIMARY KEY DEFAULT 1,
	NAME VARCHAR(30) NOT NULL,
	ADDRESS VARCHAR(30) NOT NULL,
	PHNO VARCHAR(10) NOT NULL
);

CREATE TABLE PROFESSOR (
	ID INTEGER(5) PRIMARY KEY DEFAULT 1,
	NAME VARCHAR(30) NOT NULL,
	PHNO VARCHAR(30) NOT NULL,
	DOB DATE NOT NULL
);

CREATE TABLE STUDPROF (
	SID INTEGER(5) NOT NULL DEFAULT 1,
	PID INTEGER(5) NOT NULL DEFAULT 1,
	PRIMARY KEY(SID, PID),
	FOREIGN KEY (SID) REFERENCES STUDENT (ID),
	FOREIGN KEY (PID) REFERENCES PROFESSOR (ID)
);

HBM Files Creation:

Professor.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
    <class name="Professor" table="PROFESSOR">
        <id name="id" column="ID" type="integer">
            <generator class="increment"></generator>
        </id>

        <property name="name" column="NAME" type="string"></property>

        <property name="phNo" column="PHNO" type="string"></property>

        <property name="dob" column="DOB" type="date"></property>
    </class>
</hibernate-mapping>

Student.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
    <class name="Student" table="STUDENT">
        <id name="id" column="ID">
            <generator class="increment"></generator>
        </id>

        <property name="name" column="NAME" type="string"></property>

        <property name="address" column="ADDRESS" type="string"></property>

        <property name="phNo" column="PHNO" type="string"></property>

        <set name="professors" table="STUDPROF" cascade="all" lazy="false">
            <key column="SID"></key>
            <many-to-many column="PID" class="Professor"></many-to-many>
        </set>
    </class>
</hibernate-mapping>

Java Files:

Professor.java:

package org.mybusiness.pojos;

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

public class Professor implements Serializable {

    private static final long serialVersionUID = 2286787316913029844L;

    private int id;
    private String name;
    private String phNo;
    private Date dob;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getPhNo() {
        return phNo;
    }

    public void setPhNo(String phNo) {
        this.phNo = phNo;
    }

    public Date getDob() {
        return dob;
    }

    public void setDob(Date dob) {
        this.dob = dob;
    }
}

Student.java:

package org.mybusiness.pojos;

import java.util.Set;

public class Student {

    private int id;
    private String name;
    private String address;
    private String phNo;

    private Set<Professor> professors;

    public int getId() {
        return id;
    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }

    public String getPhNo() {
        return phNo;
    }

    public void setPhNo(String phNo) {
        this.phNo = phNo;
    }

    public Set<Professor> getProfessors() {
        return professors;
    }

    public void setProfessors(Set<Professor> professors) {
        this.professors = professors;
    }
}

Functionalities:

Create Student and Professor:

public void createStudentProfessor() {

    Student student1 = new Student();
    Student student2 = new Student();

    student1.setName("Vijay");
    student1.setPhNo("3312241124");
    student1.setAddress("St Louis");

    student2.setName("Lakshmi");
    student2.setPhNo("2211221212");
    student2.setAddress("Indiana");

    Professor professor1 = new Professor();
    Professor professor2 = new Professor();

    professor1.setName("Mike");
    professor1.setPhNo("5551115551");
    professor1.setDob(new Date());

    professor2.setName("Jake");
    professor2.setPhNo("4411221144");
    professor2.setDob(new Date());

    Set<Professor> professors = new HashSet<Professor>();
    professors.add(professor1);
    professors.add(professor2);

    student1.setProfessors(professors);
    student2.setProfessors(professors);

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);

    Session s = ht.getSessionFactory().openSession();
    Transaction tx = s.beginTransaction();

    try {

        s.save(student1);
        s.save(student2);
        tx.commit();
    } catch (Exception e) {
        e.printStackTrace();
        tx.rollback();
    } finally {
        s.close();
    }
}

Retrieve Student with Professor:

public void getStudentProfessor() {

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);
    DetachedCriteria criteria = DetachedCriteria.forClass(Student.class,
            "stud");
    criteria.add(Restrictions.eq("stud.id", 1));

    List<Student> students = ht.findByCriteria(criteria);
    for (Student student : students) {

        System.out.println("STUDENT: " + student.getName() + ":"
                + student.getAddress() + ":" + student.getPhNo());
        for (Professor professor : student.getProfessors()) {
            System.out.println("PROFESSOR: " + professor.getName() + ":"
                    + professor.getPhNo());
        }
    }
}

Thursday, August 11, 2011

HIBERNATE - Bi-directional One-to-Many Association

In the following example, we will be going through the bi-directional One-to-Many association using Hibernate. We will be using the Employee and PhoneNumbers table where each Employee will have one or more phone numbers associated with him/her.

Schema Creation:

We will be creating two tables Employee and PhoneNumbers. The PhoneNumbers table has a foreign key reference to the Employee table.

CREATE TABLE EMPLOYEE (
	EMP_ID INTEGER(5) PRIMARY KEY DEFAULT 1,
	EMP_NAME VARCHAR(30) NOT NULL,
	EMP_DOB DATE NOT NULL
);

CREATE TABLE PHONENUMBERS (
	PH_ID INTEGER(5) PRIMARY KEY DEFAULT 1,
	PH_NUMBER VARCHAR(10) NOT NULL,
	EMP_ID INTEGER(5) NOT NULL,
	FOREIGN KEY (EMP_ID) REFERENCES EMPLOYEE (EMP_ID)
);

HBM Files Creation:

Employee.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
    <class name="Employee" table="EMPLOYEE">
        <id name="empId" column="EMP_ID" type="integer">
            <generator class="increment"></generator>
        </id>

        <property name="empName" column="EMP_NAME" not-null="true"
            type="string"></property>

        <property name="empDOB" column="EMP_DOB" not-null="true"
            type="date"></property>

        <set name="phoneNumbers" table="PHONENUMBERS" cascade="all"
            lazy="false" inverse="true" order-by="PH_ID ASC">
            <key column="EMP_ID" not-null="true"></key>
            <one-to-many class="PhoneNumbers" />
        </set>
    </class>
</hibernate-mapping>

PhoneNumbers.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
    <class name="PhoneNumbers" table="PHONENUMBERS">
        <id name="phId" column="PH_ID" type="integer">
            <generator class="increment"></generator>
        </id>

        <property name="phoneNo" column="PH_NUMBER" not-null="true"
            type="string"></property>

        <many-to-one name="employee" column="EMP_ID"
            not-null="true" cascade="all" class="Employee" lazy="false"></many-to-one>
    </class>
</hibernate-mapping>

Java Files:

Employee.java:

package org.mybusiness.pojos;

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

public class Employee implements Serializable {

    private static final long serialVersionUID = 4451804446997564426L;

    private int empId;
    private String empName;
    private Date empDOB;

    // Hibernate expects interfaces like Set, Map, List to be the declaration
    // because while doing retrieve operations Hibernate uses its own Set, etc
    // to fill up the contents in this variable
    private Set<PhoneNumbers> phoneNumbers;

    public Employee() {
        phoneNumbers = new LinkedHashSet<PhoneNumbers>();
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Date getEmpDOB() {
        return empDOB;
    }

    public void setEmpDOB(Date empDOB) {
        this.empDOB = empDOB;
    }

    public Set<PhoneNumbers> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setPhoneNumbers(Set<PhoneNumbers> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

    public void addPhoneNumber(PhoneNumbers phoneNumber) {
        this.phoneNumbers.add(phoneNumber);
    }
}

PhoneNumbers.java:

package org.mybusiness.pojos;

import java.io.Serializable;

public class PhoneNumbers implements Serializable {

    private static final long serialVersionUID = -3505306499633395745L;

    private int phId;
    private String phoneNo;

    // Adding Bi-directionality.
    private Employee employee;

    public int getPhId() {
        return phId;
    }

    public void setPhId(int phId) {
        this.phId = phId;
    }

    public String getPhoneNo() {
        return phoneNo;
    }

    public void setPhoneNo(String phoneNo) {
        this.phoneNo = phoneNo;
    }

    public Employee getEmployee() {
        return employee;
    }

    public void setEmployee(Employee employee) {
        this.employee = employee;
    }
}

Functionalities:

Create Employee:

Approach 1:

public void createEmployeeBidirApproach1() {

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);

    Session s = ht.getSessionFactory().openSession();
    Transaction tx = s.beginTransaction();

    try {

        // Create an employee
        Employee emp = new Employee();
        emp.setEmpName("Peter");
        emp.setEmpDOB(Calendar.getInstance().getTime());

        // Save the Employee and get the Primary Key
        Integer key = (Integer) s.save(emp);

        PhoneNumbers phNo = new PhoneNumbers();
        phNo.setPhoneNo("8765432190");
        phNo.setEmployee(emp); // Set the foreign key.

        // Save the phone number
        s.save(phNo);

        phNo = new PhoneNumbers();
        phNo.setPhoneNo("9988776655");
        phNo.setEmployee(emp);// Save the phone number

        // Save the phone number
        s.save(phNo);

        tx.commit();
    } catch (Exception e) {
        e.printStackTrace();
        tx.rollback();
    } finally {
        s.close();
    }
}

Approach 2:

public void createEmployeeBidirApproach2() {

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);

    Session s = ht.getSessionFactory().openSession();
    Transaction tx = s.beginTransaction();

    try {

        Employee emp = new Employee();
        emp.setEmpName("Jake");
        emp.setEmpDOB(Calendar.getInstance().getTime());

        // Save Employee and get the key
        Integer key = (Integer) s.save(emp);

        PhoneNumbers phNo = new PhoneNumbers();
        phNo.setPhoneNo("7865765412");
        phNo.setEmployee(emp);

        emp.addPhoneNumber(phNo);

        phNo = new PhoneNumbers();
        phNo.setPhoneNo("7766776677");
        phNo.setEmployee(emp);

        emp.addPhoneNumber(phNo);

        // Save the employee again with the phone numbers added
        s.save(emp);
        tx.commit();
    } catch (Exception e) {
        e.printStackTrace();
        tx.rollback();
    } finally {
        s.close();
    }
}

Retrieve Employee:

public void getAllEmployees() {

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);

    DetachedCriteria criteria = DetachedCriteria.forClass(Employee.class,
            "emp");
    criteria.add(Restrictions.le("emp.empId", 10));

    // NOTE: LEFT_JOIN eliminates the selection of all phone numbers from
    // the phonenumbers table. This is necessary when we want to filter out
    // the result set from the dependent entity
    DetachedCriteria child = criteria.createCriteria("emp.phoneNumbers",
            "ph", CriteriaSpecification.LEFT_JOIN);
    child.add(Restrictions.ilike("ph.phoneNo", "2", MatchMode.END));
    child.add(Restrictions.le("ph.phId", 10));
    child.addOrder(Order.desc("ph.phId"));

    // NOTE: The result transformer ensures that the result contains only
    // one Employee object with set of phone numbers. If this transformer is
    // not used, then the result set would be repeated by the number of
    // phone numbers present in the set.
    criteria
            .setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

    List<Employee> employees = ht.findByCriteria(criteria);

    int count = 1;
    for (Employee employee : employees) {
        System.out.println("Employee Index : " + count++);
        System.out.println("----------------------------");
        printEmployee(employee);
    }
}

public void getPhoneNumbersForEmployee() {

    Integer empId = 5;

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);

    DetachedCriteria criteria = DetachedCriteria.forClass(
            PhoneNumbers.class, "ph");
    criteria.createAlias("ph.employee", "emp");

    criteria.add(Restrictions.eq("emp.empId", 5));

    List<PhoneNumbers> phonenumbers = ht.findByCriteria(criteria);

    for (PhoneNumbers phNo : phonenumbers) {
        System.out.println(phNo.getPhId() + ":" + phNo.getPhoneNo() + ":"
                + phNo.getEmployee().getEmpName());
        System.out.println();
    }
}

private void printEmployee(Employee employee) {

    System.out.println("Employee Id : " + employee.getEmpId());
    System.out.println("Employee Name : " + employee.getEmpName());
    System.out.println("Employee DOB : " + employee.getEmpDOB());

    Set<PhoneNumbers> phNos = employee.getPhoneNumbers();
    System.out.println(phNos.getClass());

    if (phNos != null) {
        for (PhoneNumbers phNo : phNos) {
            System.out.println("PhNo : " + phNo.getPhId() + ", "
                    + phNo.getPhoneNo());
        }
    }
    System.out.println("---------------------------"
            + "--------------------------");
}

HIBERNATE - Unidirectional One-to-Many Association

In the following example, we will be going through the Unidirectional One-to-Many association using Hibernate. We will be using the Employee and PhoneNumbers table where each Employee will have one or more phone numbers associated with him/her.

Schema Creation:

We will be creating two tables Employee and PhoneNumbers. The PhoneNumbers table has a foreign key reference to the Employee table.

CREATE TABLE EMPLOYEE (
	EMP_ID INTEGER(5) PRIMARY KEY DEFAULT 1,
	EMP_NAME VARCHAR(30) NOT NULL,
	EMP_DOB DATE NOT NULL
);

CREATE TABLE PHONENUMBERS (
	PH_ID INTEGER(5) PRIMARY KEY DEFAULT 1,
	PH_NUMBER VARCHAR(10) NOT NULL,
	EMP_ID INTEGER(5) NOT NULL,
	FOREIGN KEY (EMP_ID) REFERENCES EMPLOYEE (EMP_ID)
);

HBM Files Creation:

Employee.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
    <class name="Employee" table="EMPLOYEE">
        <id name="empId" column="EMP_ID" type="integer">
            <generator class="increment"></generator>
        </id>

        <property name="empName" column="EMP_NAME" not-null="true"
            type="string"></property>

        <property name="empDOB" column="EMP_DOB" not-null="true"
            type="date"></property>

        <set name="phoneNumbers" table="PHONENUMBERS" cascade="all"
            lazy="false" inverse="true" order-by="PH_ID ASC">
            <key column="EMP_ID" not-null="true"></key>
            <one-to-many class="PhoneNumbers" />
        </set>
    </class>
</hibernate-mapping>

PhoneNumbers.hbm.xml:

<?xml version="1.0"?>
<!DOCTYPE hibernate-mapping PUBLIC
    "-//Hibernate/Hibernate Mapping DTD 3.0//EN"
    "http://hibernate.sourceforge.net/hibernate-mapping-3.0.dtd">
<hibernate-mapping package="org.mybusiness.pojos">
    <class name="PhoneNumbers" table="PHONENUMBERS">
        <id name="phId" column="PH_ID" type="integer">
            <generator class="increment"></generator>
        </id>

        <property name="phoneNo" column="PH_NUMBER" not-null="true"
            type="string"></property>

        <property name="empId" column="EMP_ID" not-null="true"
            type="integer"></property>
    </class>
</hibernate-mapping>

Java Files:

Employee.java:

package org.mybusiness.pojos;

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

public class Employee implements Serializable {

    private static final long serialVersionUID = 4451804446997564426L;

    private int empId;
    private String empName;
    private Date empDOB;

    // Hibernate expects interfaces like Set, Map, List to be the declaration
    // because while doing retrieve operations Hibernate uses its own Set, etc
    // to fill up the contents in this variable
    private Set<PhoneNumbers> phoneNumbers;

    public Employee() {
        phoneNumbers = new LinkedHashSet<PhoneNumbers>();
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }

    public String getEmpName() {
        return empName;
    }

    public void setEmpName(String empName) {
        this.empName = empName;
    }

    public Date getEmpDOB() {
        return empDOB;
    }

    public void setEmpDOB(Date empDOB) {
        this.empDOB = empDOB;
    }

    public Set<PhoneNumbers> getPhoneNumbers() {
        return phoneNumbers;
    }

    public void setPhoneNumbers(Set<PhoneNumbers> phoneNumbers) {
        this.phoneNumbers = phoneNumbers;
    }

    public void addPhoneNumber(PhoneNumbers phoneNumber) {
        this.phoneNumbers.add(phoneNumber);
    }
}

PhoneNumbers.java:

package org.mybusiness.pojos;

import java.io.Serializable;

public class PhoneNumbers implements Serializable {

    private static final long serialVersionUID = -3505306499633395745L;

    private int phId;
    private String phoneNo;
    private int empId;

    public int getPhId() {
        return phId;
    }

    public void setPhId(int phId) {
        this.phId = phId;
    }

    public String getPhoneNo() {
        return phoneNo;
    }

    public void setPhoneNo(String phoneNo) {
        this.phoneNo = phoneNo;
    }

    public int getEmpId() {
        return empId;
    }

    public void setEmpId(int empId) {
        this.empId = empId;
    }
}

Functionalities:

Create Employee:

Approach 1:

public void createEmployeeApproach1() {

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);

    Session s = ht.getSessionFactory().openSession();
    Transaction tx = s.beginTransaction();

    try {

        // Create an employee
        Employee emp = new Employee();
        emp.setEmpName("Vijay");
        emp.setEmpDOB(Calendar.getInstance().getTime());

        // Save the Employee and get the Primary Key
        Integer key = (Integer) s.save(emp);

        PhoneNumbers phNo = new PhoneNumbers();
        phNo.setPhoneNo("3143143142");
        phNo.setEmpId(key); // Set the foreign key.

        // Save the phone number
        s.save(phNo);

        phNo = new PhoneNumbers();
        phNo.setPhoneNo("3221322132");
        phNo.setEmpId(key);// Save the phone number

        // Save the phone number
        s.save(phNo);

        tx.commit();
    } catch (Exception e) {
        e.printStackTrace();
        tx.rollback();
    } finally {
        s.close();
    }
}

Approach 2:

public void createEmployeeApproach2() {

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);

    Session s = ht.getSessionFactory().openSession();
    Transaction tx = s.beginTransaction();

    try {

        Employee emp = new Employee();
        emp.setEmpName("Steve");
        emp.setEmpDOB(Calendar.getInstance().getTime());

        // Save Employee and get the key
        Integer key = (Integer) s.save(emp);

        PhoneNumbers phNo = new PhoneNumbers();
        phNo.setPhoneNo("1221221221");
        phNo.setEmpId(key);

        emp.addPhoneNumber(phNo);

        phNo = new PhoneNumbers();
        phNo.setPhoneNo("2212212212");
        phNo.setEmpId(key);

        emp.addPhoneNumber(phNo);

        // Save the employee again with the phone numbers added
        s.save(emp);
        tx.commit();
    } catch (Exception e) {
        e.printStackTrace();
        tx.rollback();
    } finally {
        s.close();
    }
}

Retrieve Employee:

public void getAllEmployees() {

    HibernateTemplate ht = new HibernateTemplate(sessionFactory);

    DetachedCriteria criteria = DetachedCriteria.forClass(Employee.class,
            "emp");
    criteria.add(Restrictions.le("emp.empId", 5));

    // NOTE: LEFT_JOIN eliminates the selection of all phone numbers from
    // the phonenumbers table. This is necessary when we want to filter out
    // the result set from the dependent entity
    DetachedCriteria child = criteria.createCriteria("emp.phoneNumbers",
            "ph", CriteriaSpecification.LEFT_JOIN);
    child.add(Restrictions.ilike("ph.phoneNo", "2", MatchMode.END));
    child.add(Restrictions.le("ph.phId", 10));
    child.addOrder(Order.desc("ph.phId"));

    // NOTE: The result transformer ensures that the result contains only
    // one Employee object with set of phone numbers. If this transformer is
    // not used, then the result set would be repeated by the number of
    // phone numbers present in the set.
    criteria
            .setResultTransformer(CriteriaSpecification.DISTINCT_ROOT_ENTITY);

    List<Employee> employees = ht.findByCriteria(criteria);

    int count = 1;
    for (Employee employee : employees) {
        System.out.println("Employee Index : " + count++);
        System.out.println("----------------------------");
        printEmployee(employee);
    }
}

private void printEmployee(Employee employee) {

    System.out.println("Employee Id : " + employee.getEmpId());
    System.out.println("Employee Name : " + employee.getEmpName());
    System.out.println("Employee DOB : " + employee.getEmpDOB());

    Set<PhoneNumbers> phNos = employee.getPhoneNumbers();
    System.out.println(phNos.getClass());
    
    if (phNos != null) {
        for (PhoneNumbers phNo : phNos) {
            System.out.println("PhNo : " + phNo.getPhId() + ", "
                    + phNo.getPhoneNo());
        }
    }
    System.out.println("---------------------------"
            + "--------------------------");
}