Wednesday, July 23, 2008

Inheritance Strategy - Class per hierarchy

Hibernate supports several types of inheritance strategies in which simplest of them is "Class-per-heirarchy". In this strategy, data for all classes involved in inheritance is stored in a single table and a record is identified by discriminator column. Lets discuss this strategy with an example. Suppose there are three classes: Person, Employee, and Physician. Inheritance relationship is shown in the fig below:Person is an abstract class. So either a person will exist as Employee or Physician. Hibernate mapping for Person is shown below:


Discriminator element creates a column with name "Type", value of which will indicate whether a particular record is Employee or Physician. There is also a special property "abstract" in class element which tells that object of person can't be created.

Hibernate mapping for Employee is shown below:



"subclass" element indicates that there is a class per hierarchy strategy of inheritance between Employee and Person. "extends" property of subclass element creates relationship of "Employee" with "Person". "discriminator-value" tells hibernate to use "Employee" in discriminator column to identify all employees.

Configuration for Physician is given below:



Now lets add two Persons: one is Employee and other is Physician as shown below:

Session session = HibernateUtil.getSessionFactory().openSession(); session.beginTransaction(); Emplo
yee emp = new Employee(); emp.setName("Amer Sohail"); emp.setPay(123f); session.save(emp); Physician phy = new Physician(); phy.setName("Dr. Amer Sohail"); phy.setPay(345f);
phy.setBillingAddress("Lahore");
phy.setSpeciality("Pediatrics");
session.save(phy); session.getTransaction().commit(); session.close();


a single table with name "person" will be created in the database with following two records:


Lets retrieve the all person from database and you will observe polymorphic feature of hibernate:

Session session = HibernateUtil.getSessionFactory().openSession();
session.beginTransaction();
List emp = session.createQuery("from Person emp").list();
if (emp != null && emp.size() > 0)
{
for (int index = 0; index <>
{
System.out.println("Name of employee is " +((Employee)emp.get(index)).getName());
if (emp.get(index) instanceof Person)
System.out.println("This is person");

if (emp.get(index) instanceof Employee)
System.out.println("This is Employee");

if (emp.get(index) instanceof Physician)
System.out.println("This is Physician");
}
}
session.getTransaction().commit();
session.close();


output of the code will be following:

Name of employee is Amer Sohail
This is person
This is Employee
Name of employee is Dr. Amer Sohail
This is person
This is Employee
This is Physician

As shown in output, i just retrieved "persons" but it instantiated objects of type to which they belong e.g. Amer Sohail was just an employee not a physician so hibernate created it of "Employee" type. This is really a very powerful feature of hibernate.

Now if i want to retrieve only employee not physician, then i will write the following query:


List emp = session.createQuery("from Employee emp where type = Employee").list();


I explained the strategy "class-per-heirarchy" in this blog's post. This strategy has one major drawback which you should notice while viewing records in table. It contains "nulls" against those records which are not in employee like "speciality" and "billing_address". Since DBMS has to handle null fields with a special case and it creates an impact on performance so that is the major drawback of this strategy because it will create a lot of nulls in the table. but on the other handle, no join is needed so no join cost improves the performance. Now there is very interesting situation bcz pros of this blog says it increase the performance while cons says it decreases the performance so what is the net effect. you have to wait for it for later posts in which i will compare all the strategies.

Saturday, July 19, 2008

Batch Insertion in Hibernate

Batch Insertion is a powerful feature of hibernate particularly useful when you are importing data from other systems in batch. If you do not use batch feature of hibernate, your application's performance may decrease dramatically at the time of insertion of many records.
There are two approaches in hibernate to handle batch insertion. Each one is explained below:

  • One approach is related to Session class. Let's discuss it with example. Suppose there is an application for library which uses hibernate as ORM layer. Now you want to insert 1 million books in library. For simplicity domain model contains two classes one is book and second one is publisher. Publisher is contained in book class and i have enabled cascade insert and cascade update so if i insert book which contains publisher that is not in the system, it will also be saved with book. Code to insert books are given below:

    Session session =HibernateUtil.getSessionFactory().openSession(); session.beginTransaction();
    for (int index = 0; index <> Book book = new Book();
    book.setAuthor("amer");
    book.setIsbn("34343");
    book.setName("Hibernate " + index);
    Publisher pub = new Publisher();
    pub.setName("Publisher " + index);
    book.setPublisher(pub);
    book.setPublishDate(new Date());
    session.save(book);
    }
    session.getTransaction().commit();
    session.close();


Above code is putting a lot of memory burden because whenever an object is saved, hibernate puts that object in cache which is called as "session cache" or "first level of cache" and probably you will face an error of Stack outofflow memory error. In order to avoid this, you have to clear the session, but question is when session should be cleared either after each insertion of after some interval. If you clear session, after each insertion, it will decrease your applications' performance dramatically because before calling clear operation on session, you have to call flush operation which will synchronize persistent data store to objects memory states. For this situation, there comes a concept of batch insertion. For batch insertion, first of all you will have to add "hibernate.jdbc.batch_size" property in your hibernate.cfg.xml file with value of 50.

By using this property, hibernate will use jdbc for batch insertion of 50 records at a time when you flush the session. Batch size "50" is my recommendation because i always got max application performance with this number. You also have to change code to flush objects from session as below:

session.save(book); if (index % 50== 0) { session.flush(); session.clear(); }

  • Second way of doing batch insertion is through "StatelessSession" class. StatelessSession class differs from Session class in that it does not cache the objects, does not call interceptors, does not save any persistence context of object, does not cascade to composed objects, does not take care of collections, directly transfers the object to jdbc insert statement. So in other way it is more close to jdbc. With StatelessSession, you have to save composed objects separately e.g. in above example, you have to insert publisher and books separately. Above code with StatelessSession will be:


    StatelessSession session = HibernateUtil.getSessionFacgtory().openStatelessSession(); session.beginTransaction();
    for (int index = 0; index < style="font-style: italic; color: rgb(255, 153, 102);"> {
    Book book = new Book();
    book.setAuthor("amer");
    book.setIsbn("34343");
    book.setName("Hibernate " + index);
    Publisher pub = new Publisher();
    pub.setName("Publisher " + index);
    book.setPublisher(pub);
    book.setPublishDate(new Date());
    session.insert(pub);
    session.insert(book);
    }
    session.getTransaction().commit();
    session.close();

Well its time now to conclude the things. I have used both ways and i prefer first approach over second one because of the following reasons:
  • StatelessSession does not provide any performance over Session when you have to save composed instances too.
  • It does not call any interceptors or evens which may complicate the application design if we heavily depend on interceptors or events for logging or data level security etc.
  • Even for a plain object, StatelessSession does not provide me much performance over Session. It only provided me performance when an object contains one or two attributes. e.g. if i only insert publisher through StatelessSession, i will get performance by 20 to 30 seconds.

Saturday, July 5, 2008

Packaging j2se application in jar

Jar file is distributable unit for j2se applications. It is a zipped file but with jar extension. Jar file contains following contents:

- Java compiled classes
- manifest.mf file which contains meta info regarding jar like name of main class, jars to be added in classpath etc, version info etc. (optional)
- other jars on which classes of this jar depends (optional)

There are two types of jars:

- Library Jar
- Executable Jar

Difference between the two jars is simply a main class. If your application runs standalone and contains main class, then you put name of main class in manifest file. This makes a jar an executable jar. You can run your executable jar just by double clicking on it or through java command with switch -jar. On the other hand, library jar does not contain any main class, and it always runs as a dependency jar for other java applications.

Now lets see how we can create a library jar
If you project just contains java classes and no other jars or manifest file, then you will create jar using following command:

project-folder>jar cvf mylibrary.jar -C classes .

cvf are three switches for jar. "c" means i want to create a new jar rather than updating previous one. "v" means i want to print all log info on console. "f" means supply an output to file i.e. mylibrary.jar in this case. -C is another switch which is used to tell which folders you want to include in jar. In my case all compiled java files are under classes folder but i don't want to include classes folder itself in jar so i used "-C classes .". Dot "." here tells jar command not to include classes folder. If you omit ".", then you have to change switch -C with this "-C classes/". it will tell jar command that all compiles files are under classes folder and include classes folder itself in jar file.
if you look at the contents of created jar file using any unzipped software, you will find that it contains classes + one more folder named as "META-INF". This folder contains manifest.mf. By default jar creates manifest.mf itself if you don't provide it. If you open this manfiest.mf using any text editor, you will see it just contains following two entries:

Manifest-Version: 1.0
Created-By: 1.6.0_03 (Sun Microsystems Inc.)

Important one is "Created-By" which tells which version of java was used to package jar file. In this case it is jse 6 with update 3.
If classes depend on other jars, you have to include those jars in classpath. This can be done at the time of running a program or writing all dependencis in manifest file, so java will automatically add it to classpath. Suppose above jar "mylibrary.jar" depends on other jars named as "other1.jar" and "other2.jar". Now to include these two jars in classpath through manifest file. Create a text file with any name let dependencies.txt and add following lines:

Class-Path: other1.jar other2.jar

Keep in mind that you have to provide spaced in between the every two jar file names.

Now you can add this manifest file to already created manifest file using following command:

project-folder> jar uvfm mylibrary.jar dependencies.txt

Console output will show that Manifest.mf updated. In this command i used switch "u" instead of "c" because i want to append manifest in already created jar. I also used "m" switch, which is used when you want to provide your own manifest file. If i want to create new jars with my own manifest file, then i have to use following command:

project-folder> jar cvfm mylibrary.jar dependencies.txt -C classes .

It is the same command as used previously to create jar with exception of extra "m" switch and name of manifest file.

Procedure of creating executable jar file is the same as library jar but you have to provide one extra attribute in your manifest file with name "Main-Class", So if i have name of main class as "org.engineers.java.MyMain", then i will have to added one entry in manifest file as:

Main-Class: org.engineers.java.MyMain

Saturday, June 21, 2008

Compiling and Executing Java program

There are three basic steps in development of a simple java program which are Coding, Compiling, and Executing the java program. Coding is to write different set of classes and interfaces using any text editor like notepad etc. There are three cases which a java program can have. Those are:

Case A: Classes in default package (no package) and does not use classes which are bundled in jar.
Case B: Classes which are grouped in different packages but does not use classes which are bundled in jar.
Case C: Classes which are group in different packages and also uses classes bundled in jar.

Now i discuss compilation and execution of java program in each case one by one.

Lets discuss Case A. It is most simplest case which does not have any dependency on classes of others which are bundled in jar. Morever, classes are not grouped in different packages. Classes which are not grouped in packages, are said to be contained in default package. Suppose you have created a folder named as "TestProject" and has placed all java files there, then you can do following in windows to compile and exeuctge java program:
Just go to directory "TestProject" through command prompt and write following command:
C:\TestProject>javac *
above command will compile all java files. Now In order to run the java program, write following command:
C:\TestProject>java MainClass
where MainClass is any class which contains "public static void main(String[] args)" method.

Now we discuss Case B in which classes are grouped under packages. Packages provide better management of code, easy maintenance, and good access control on classes. Morever, packages provide safety from class name collissions. This case has further two possibilities. One is that you have logical grouped java classes in packages but placed them together like in case A i.e. all classes in folder TestProject. Now you will use following command to compile the code:
C:\TestProject>javac * -d .
"d" switch is used to provide destination for compiled classes. When destination is ".", it means root directory (TestProject in this case) will be default directory. javac command will first create folder heirarchy similar to packages and will place compiled class files in respective folder e.g. if a class is in package "org.engineers.project", then javac will first create folder named as "org" at root directory, then will create "engineers" folder under "org" and "project" folder under "engineers" folder. and will place class in "project" folder. In order to execute java program, you have to write following command at root directory:
C:\TestProject>java fully_qualified_class_name
fully_qualified_class_name means name of class with package e.g. if a class "Main" is contained under package org.engineers.project, then fully_qualified_class_name will be "org.engineers.project.Main"

Now we talk about second possibility in Case B which is that you have placed java source files in same folder hierarchy, as of packages i.e. if a class "Main.java" is in package "org.engineers.project", you have placed Main.java in folder org/engineers/project folder. You can use same command to compile and execute java program as in first possibility but it will mix your compiled code with source code so in order to keep them separate create a directory named as "src" under root directory (TestProject in this case) and then place all folder hierarchy containing source files there. Now create another folder named as "classes" at root level and use following command to compile the code:
C:\TestProject>javac * -d classes
"classes" folder be treated as root folder for class files.
In order to run java program, you have to change java command slightly. New command will be:
C:\TestProject>java -cp classes org.engineers.project.Main
Difference with this command and with previous command is of addition switch named as "cp". it represents classpath and tells java command where to find compiled classes. Since compiled classes are in "classes" folder, so i added that folder in classpath.

Now its time to discuss Case C, which is more realistic case. In this case, java source files uses classes which are placed in "jar" file. Jar file is just a zip file but with extensino java archive ("jar") . Now you will have to include all jar files in classpath using same switch which we used in preceding case to run the program. but this time we will have to use switch in both javac and java command.
C:\TestProject> javac -cp test.jar * -d classes
where test.jar is jar file which contains other classes which my classes use.
To execute the java program use following command:
C:\TestProject> java -cp test.jar;classes org.enigneers.project.Main
Note that i have added both "test.jar" and "classes folder in classpath.

Saturday, June 14, 2008

Cloning of Java objects

Parent class of all objects in java is "Object" which contains several important methos. One of them is "clone" which is used to make a copy of object. There are certain things which you should keep in mind while using clone method of Object.
- implement "Cloneable" interface to each class which you want to clone. If a class does not implement "Cloneable" interface, clone method will throw "CloneableNotSupportedException". This interface does not contain any methods. It is just a marker interface. Suppose you have a Class "Book" of which you want to make a clone, then structure of that class will be:

public class Book implements Cloneable
{
//attributes
//methods
@Override protected Object clone() throws CloneableNotSupportedException
{
//Clone logic
}
}

- Obtain cloned object through super.clone
- if your class only contains primitive attributes or wrappers of primitive attributes or immutable object like String, then you don't need to do anything special inside clone method because clone method automatically makes a copy of primitive data types and immutable objects. Suppose above "Book" class contains following two attributes with accessor methdos for attributes:

private String name;
private Float price;
public String getName() {
return name;
}

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

public Float getPrice() {
return price;
}

public void setPrice(Float price) {
this.price = price;
}

Now to clone Book class you just need to write following implementation in overriding of clone method:

protected Object clone() CloneNotSupportedException
{
return super.clone();
}

- by default clone method makes shallow copy and does not make a Deep copy of object. Deep copy means if your object contains references of other objects or collections, it will not make a copy of those referenced objects and will use same references as was in origianl objects. Suppose above mentioned "Book" class contains an attribute of class "Publisher". Structure of Publisher class is given below:


public class Publisher{
private String pubName;

public String getPubName() {
return pubName;
}

public void setPubName(String pubName) {
this.pubName = pubName;
}
}

Now try out the following code:

Publisher pub = new Publisher();
pub.setPubName("Java Publisher");
orig.setPub(pub);
Logger.getLogger(CloneTest.class.getName()).log(Level.INFO,orig.getPub().getPubName());
Book clone2 = (Book) orig.clone();
Logger.getLogger(CloneTest.class.getName()).log(Level.INFO,clone2.getPub().getPubName());
orig.getPub().setPubName("java Publisher Changed");
Logger.getLogger(CloneTest.class.getName()).log(Level.INFO,clone2.getPub().getPubName());

Output of above code will be:
15-Jun-2008 1:39:47 AM javasolutionsblog.clonetest.CloneTest main
INFO: Java Publisher
15-Jun-2008 1:39:47 AM javasolutionsblog.clonetest.CloneTest main
INFO: Java Publisher
15-Jun-2008 1:39:47 AM javasolutionsblog.clonetest.CloneTest main
INFO: Java Publisher Changed


Although expected output of third log was "Java Publisher" but since clone didn't make copy of refernce object publisher, it used same object in clone as in origignal object, when i make a change in the publisher name in original object, it also reflected in cloned object.

- In order to do deep copy of Book class, we will aso have to implement "Cloneable" interface in "Publisher" class + override clone method in Publisher class too. If Publisher class contains references of other objects, then you will have to implement Cloneable interface + override clone method in each sub class too.
In our case, structure of Publisher class will be:

public class Publisher implements Cloneable{
private String pubName;

public String getPubName() {
return pubName;
}

public void setPubName(String pubName) {
this.pubName = pubName;
}

@Override
protected Object clone() throws CloneNotSupportedException
{
return super.clone();
}

}

Now change the definition of clone method of Book class as follows:

protected Object clone() throws CloneNotSupportedException {
Book clonedBook = (Book) super.clone();
if (this.getPub() != null) {
clonedBook.setPub((Publisher) this.getPub().clone());
}

return clonedBook;
}

Thursday, June 12, 2008

Implementing Equals and HashCode

In my last blog i described how we can compare two java objects of same class by overriding equals method. In this blog i will explain best practices regarding implementing of equals method.
Whenever, we go for overriding of equals method, one question comes to our mind is, on which basis we will have to say that two objects are same. First answer comes to mind is that we should compare objects on the basis of primary key which is also used to distinguish the records in the database. Primary keys are good candidate to compare objects if we assign primary keys ourself not by database. When primary key is assigned by database like auto number, objects don't have primary key until they are persisted in the database so before persistent of objects, how we should compare the objects. Good practice is always compare objects on the basis of business key which uniquely describes objects. Suppose we have a class of Person with attributes (id, name, ssn,address) . In this class we have two unique attributes one is id and second one is ssn. id is used to distinguish the objects in the database and is assigned when objects are persisted, then only choice is SSN which we can use to compare different person because each person has his own SSN (Social Security Number). So best practice is always compare objects on business keys rather than on database keys.
Second best practice is whenever you go for overriding of equals method. also override "int hashCode()" method. This method returns hash of objects. Implementing hasCode facilitates us when we use objects as keys in HashTable. If we don't override hashCode method, each object created with new operator will always has different hash values irrespective of fact whether they are same or not. Suppose I have a class of Customer with attributes (id, name, ssn, address) and i create two objects with new operation having the same dataset. Although logically they are same but physically they are two different objects that's y they have differnt hashCode. So best practice is that if two objects are equals, then those two objects should always have same hashCode. Overriding of hashCode will also facilitate us when we save objects in sets. Sets store only one instance of an object at a time, so if we have two customer objects with same attributes, then only one instance of customer must be saved in sets. It is only possible by overriding of hashcode method.
Now question is how to generate hashCode for an object. Answer is same as for equals method. Always generate hashCode from business keys. In above example of Customer objects, we should generate hashCode of Customer from SSN. java has provided methods which generate hashCode for all primitive data types and for String. hashCode for primitive data types are generated by using wrappers of primitive data types e.g. for int we can generate hashCode by following code:

Integer i = new Integer(5);
int code = i.hashCode();

Similary we can get hashCode of other primitive datatypes by using respective wrapper classes.

So in this blog we have come to Two Best Practices regarding comparison of objects:
- One is always compare objects in equal method on the basis of business keys.
- Second is whenever override equals method, also override hashCode method and generate hash for objects on the basis of same business key as used in equals method.

Saturday, May 3, 2008

Comparison of Objects with equals

== relational operator is used to compare basic data types in java e.g. if we want to compare two integers, we will do it as follows:

int a = 5;
int b = 5;
if (a == b)
System.out.println("equal");
else
System.out.println("not equal");

Output of above java code will be "equal". but this "==" operator works only with basic data types, even it will not work if we use wrapper classes of basic data types e.g.

Integer a = new Integer(5);
Integer b = new Integer(5);
if (a == b)
System.out.println("equal");
else
System.out.println("not equal");


Output of above code will be "not equal". Why "==" operator does not applicable for objects is that because it compares two references of object not contents of objects. Now for comparison of contents of objects there is "equals" method in each object e.g. if we change above comparison of wrapper classes with this code, it will work correctly:

Integer a = new Integer(5);
Integer b = new Integer(5);
if (a.equals(b))

System.out.println("equal");
else
System.out.println("not equal");

Output of above code will be "equal" This "equals" work fine for wrapper classes but does not run correctly for custom classes because it compares two object references by default just like "==" operator. To change behaviour of "equals" we will have to override it in our classes. Suppose i have a class "Book" which has attributes like name, isbn, author, publisher. Now uniqueness of book is checked using isbn number so to compare two books, override "equals" method and in that implementation check the "isbn" of book. Code Structure is given below:

public class Book{
private String isbn;
private String name;
private String author;

public String getIsbn() {
return isbn;
}

public void setIsbn(String 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;
}

@Override
public boolean equals(Object obj) {
Book book = (Book)obj;
if (this.isbn.equals(book.getIsbn()))
return true;

return false;
}

public static void main(String args[]) {
Book b1 = new Book();
b1.setName("Java");
b1.setAuthor("Amer");
b1.setIsbn("12334");
Book b2 = new Book();
b2.setName("Java");
b2.setAuthor("Amer");
b2.setIsbn("12334");
if (b1.equals(b2))
System.out.println("equal");
else
System.out.println(" not equal");
}
}

output of above code will be equal. even if name or author of two are different because my implementation of "equals" just checks for "isbn".

In my later post, i will exlain best practices related to overriding of "equals" method.