Tuesday, October 17, 2006

Java 5, EJB 3 Persistence and Hibernate annotations

Java 5, EJB 3 Persistence and Hibernate annotations

I finally decided to try out some code with Java 5 annonations. For this I chose to try hibernate annotations implementation, which implements EJB 3 persistence with some enhanced annotations of its own.

Pre -requisites
1) Java 5 SDK
2) Latest Hibernate jar with dependent libraries from the lib folder of the download.
3) Latest Hibernate annotation jar with dependent libraries from the lib folder of the download.
4) Ant

Domain Objects

The domain objects are Person and Child. The relationship is one-to-many from person to child and many-to-one from Child to person. The java POJO's are fairly straight forward for this, so I will share the xml here.

Person.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>

<class name="test.suchak.hibernatetest.domainobjects.Person" table="Person">
<id
name="ID"
column="ID"
>
<generator class="sequence">
<param name="sequence">PERSONIDSEQUENCE</param>
</generator>
</id>
<property name="firstName">
<column name="FirstName"/>
</property>
<property name="lastName">
<column name="LastName"/>
</property>

<list name="children" cascade="all" inverse="true">
<key column="parent_id"/>
<index column="child_id"/>
<one-to-many class="test.suchak.hibernatetest.domainobjects.Child"/>
</list>

</class>

</hibernate-mapping>


Child.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>

<class name="test.suchak.hibernatetest.domainobjects.Child" table="Child">
<id
name="child_id"
column="child_id"
>
<generator class="sequence">
<param name="sequence">CHILDIDSEQUENCE</param>
</generator>
</id>
<property name="name">
<column name="name"/>
</property>
<property name="age">
<column name="age"/>
</property>
<many-to-one name="person"
column="parent_id"
class="test.suchak.hibernatetest.domainobjects.Person"
cascade="all"
/>
</class>

</hibernate-mapping>



XML Session factory configuration
The session factry configuration here is prettty simple. Just read the hbm files and pass them to the hibernate configugation.

public class MyHibernateSessionFactory {
......
private void buildSessionFactory(String[] fileNames) {

Configuration config = new Configuration();

for(int i=0;i<filenames.length;i++){
config.addFile(hbmDir + File.separator + fileNames[i]);
}
sessionFactory = config.buildSessionFactory();
} ....
}


Now the sessionFactory.openSession() method will retun the sessions we need. Using the session we can now do CRUD on the child and person POJO's, in the traditional hibernate world.

Annotations

Now instead of the xml files we will use annotations for the same two POJO's person and child.

Person.java


package test.suchak.hibernatetest.domainobjects;

import java.util.List;
//import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.OneToMany;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;
import org.hibernate.annotations.MapKey;
import javax.persistence.CascadeType;

/**
* @author Suchak.Jani
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*
*/

@Entity
@Table(name="Person")
public class Person {
private Integer ID;
private String firstName;
private String lastName;
private List children;

public Person(){

}
/**
* @param firstName2
* @param lastName2
*
*/
public Person(String firstName, String lastName) {
this.firstName=firstName;
this.lastName=lastName;
}

/**
* @return Returns the firstName.
*/
@Column(name = "FirstName")
public String getFirstName() {
return firstName;
}
/**
* @return Returns the iD.
*/
@Id @GeneratedValue(generator="sequence")
@GenericGenerator(name="sequence", strategy = "sequence",
parameters = {
@Parameter(name="sequence", value="PERSONIDSEQUENCE")
}
)
public Integer getID() {
return ID;
}
/**
* @return Returns the lastName.
*/
@Column(name = "LastName")
public String getLastName() {
return lastName;
}
/**
* @param firstName The firstName to set.
*/
public void setFirstName(String firstName) {
this.firstName = firstName;
}
/**
* @param id The iD to set.
*/
public void setID(Integer id) {
ID = id;
}
/**
* @param lastName The lastName to set.
*/
public void setLastName(String lastName) {
this.lastName = lastName;
}

/**
* @return Returns the children.
*/
@OneToMany(mappedBy="person", cascade=CascadeType.ALL)
//@OneToMany(mappedBy="person")
@MapKey(columns=@Column(name="child_id"))
public List getChildren() {
return children;
}
/**
* @param children The children to set.
*/
public void setChildren(List children) {
this.children = children;
}
}


Child.java


package test.suchak.hibernatetest.domainobjects;

//import javax.persistence.*;
import javax.persistence.Entity;
import javax.persistence.Table;
import javax.persistence.Column;
import javax.persistence.GeneratedValue;
import javax.persistence.ManyToOne;
import javax.persistence.JoinColumn;
import javax.persistence.Id;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.annotations.Parameter;

/**
* @author Suchak.Jani
*
* TODO To change the template for this generated type comment go to
* Window - Preferences - Java - Code Style - Code Templates
*/
@Entity
@Table(name="Child")
public class Child {

private Integer child_id; // ID
private String name;
private Integer age;
private Person person;


// need a default cosntructor for hibernate to be able to read for this object
public Child() {

}

/**
* @param parent_id2
* @param name2
* @param age2
*/
public Child(Person person,String name, Integer age) {

this.setPerson(person);
this.setName(name);
this.setAge(age);
}
/**
* @return Returns the age.
*/
@Column(name = "age")
public Integer getAge() {
return age;
}
/**
* @param age The age to set.
*/
public void setAge(Integer age) {
this.age = age;
}
/**
* @return Returns the child_id.
*/
@Id @GeneratedValue(generator="sequence")
@GenericGenerator(name="sequence", strategy = "sequence",
parameters = {
@Parameter(name="sequence", value="CHILDIDSEQUENCE")
}
)
public Integer getChild_id() {
return child_id;
}
/**
* @param child_id The child_id to set.
*/
public void setChild_id(Integer child_id) {
this.child_id = child_id;
}
/**
* @return Returns the name.
*/
@Column(name = "name")
public String getName() {
return name;
}
/**
* @param name The name to set.
*/
public void setName(String name) {
this.name = name;
}

/**
* @return Returns the person.
*/
@ManyToOne
@JoinColumn(name="parent_id",nullable=false)
public Person getPerson() {
return person;
}
/**
* @param person The person to set.
*/
public void setPerson(Person person) {
this.person = person;
}
}


Annotation Session factory configuration

The session factry configuration here is different than the xml session factory as shown below.


public class AnnotationHibernateSessionFactory {
....
/**
* @param files
*/
private void buildSessionFactory() {
try {
sessionFactory = new AnnotationConfiguration()
.addAnnotatedClass(Person.class)
.addAnnotatedClass(Child.class)
.buildSessionFactory();
} catch (Throwable ex) {
// Log exception!
throw new ExceptionInInitializerError(ex);
}
}


Key Points

1) XML files not needed.
2) An import per annotation used in the POJO.
3) (inverse="true") is now equivalent to mappedBy.
4) Most annotations are in javax.persistence package.
5) The new AnnotationConfiguration class is to be used instead of the Configuartion class.
6) The xml tags class and class name are not necessary.

Code

The working code is available for download below.

hibernatejdk5test
hibernatejdk5test....
Hosted by eSnips

0 Comments:

Post a Comment

<< Home