Java Persistence API (JPA ) Mapping
Java Platform, Enterprise Edition 5 (Java EE 5) focuses on making
development easier, yet retains the richness of the J2EE 1.4 platform.
Offering new and updated features such as Enterprise JavaBeans (EJB)
Technology 3.0, JavaServer Faces (JSF) Technology, and the latest web
services APIs, Java EE 5 makes coding simpler and more straightforward,
but maintains the power that has established Java EE as the premier
platform for web services and enterprise application development.
This hands-on lab takes you through the basic mapping features of
JPA.
The features that
will be covered in this lab include
- Building an application that uses one-to-many mapping.
- Exercising SINGLE_TABLE and JOINED inheritance strategies of Java
Persistence API
(JPA)
Expected duration: 60 minutes
Software Needed
Before you begin, you need to install the following software on your
computer.
- Java Standard Development Kit (JDK™) version
6.0 (download)
- If you already have installed JDK 5.0 or JDK 6.0, you
can skip this.
- NetBeans IDE 6.1 (download)
- When you install NetBeans IDE, it will ask you which JDK
you want to use.
- 4321_jpamapping.zip (download)
- It contains this document and the lab contents
- Download it and unzip in a directory of your choice
Change Log
- Sep. 10th, 2007: Created
- Dec. 6th, 2007: Workaround on NetBeans 6 not supporting "Creating
JSF pages from Entities" feature" is described
- Feb. 24th, 2008: Projects are now using
NetBeans 6.0 and GlassFish v2.
- June 10th, 2008: NetBeans 6.1 is used
- Sep. 6th, 2008: Exercise 1 -
CustomerHasManyOrders sample application is added. Exercise 2- there is
a bug in NetBeans 6.1 that prevents this exercise to work as described
in the lab document. This is fixed in NetBeans 6.5. And
there is a work-around for NetBeans 6.1.
Things to be done (by Sang Shin)
Lab Exercises
Exercise 1: Build and run
"CustomerHasManyOrders" sample application
(1.1)
Create a new database
(1.2)
Build and run the application
(1.3)
Look under the hood of the application
1. Customer.java
package entity;
import java.io.Serializable;
import javax.persistence.*;
import static javax.persistence.CascadeType.*;
import java.util.Collection;
import java.util.ArrayList;
/**
* @author Marina Vatkina
*/
@Entity
public class Customer implements Serializable {
private int id;
private String name;
private Collection<Order> orders = new
ArrayList<Order>();
@Id
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;
}
@OneToMany(cascade
= ALL, mappedBy = "customer")
public
Collection<Order> getOrders() {
return orders;
}
public void setOrders(Collection<Order>
newValue) {
this.orders = newValue;
}
}
|
2. Order.java
package entity;
import javax.persistence.*;
/**
* @author Marina Vatkina
*/
@Entity
@Table(name = "ORDER_TABLE")
public class Order {
private int id;
private String address;
private Customer customer;
@Id
@Column(name = "ORDER_ID")
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Column(name = "SHIPPING_ADDRESS")
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
@ManyToOne()
@JoinColumn(name = "CUSTOMER_ID")
public
Customer getCustomer() {
return customer;
}
public void setCustomer(Customer customer) {
this.customer = customer;
}
}
|
3. Client.java
package client;
import javax.persistence.EntityManager;
import javax.persistence.Persistence;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Query;
import java.util.Collection;
import java.util.List;
import entity.*;
/**
* @author Marina Vatkina
*/
public class Client {
private static EntityManagerFactory emf;
private static EntityManager em;
public static void main(String[] args) {
// Create EntityManagerFactory for persistent unit named "pu1"
// to be used in this test
emf = Persistence.createEntityManagerFactory("pu1");
// Persist all entities
createTransactionalEntityManager();
System.out.println("Inserting Customer and Orders... " + testInsert());
closeTransactionalEntityManager();
// Test query and navigation
createEntityManager();
System.out.println("Verifying that all are inserted... " +
verifyInsert());
closeEntityManager();
// Get a detached instance
in a new EntityManager
createEntityManager();
Customer c =
findCustomer("Joe Smith");
closeEntityManager();
// Remove all entities
createTransactionalEntityManager();
System.out.println("Removing
all... " + testDelete(c));
closeTransactionalEntityManager();
// Query the results
createEntityManager();
System.out.println("Verifying that all are removed... " +
verifyDelete());
closeEntityManager();
}
private static String testInsert() {
// Create new customer
Customer customer0 = new
Customer();
customer0.setId(1);
customer0.setName("Joe
Smith");
// Persist the customer
em.persist(customer0);
// Create 2 orders
Order order1 = new Order();
order1.setId(100);
order1.setAddress("123 Main
St. Anytown, USA");
Order order2 = new Order();
order2.setId(200);
order2.setAddress("567 1st
St. Random City, USA");
// Associate orders with the customer. The association
// must be set on both sides of the relationship: on the
// customer side for the orders to be persisted when
// transaction commits, and on the order side because it
// is the owning side.
customer0.getOrders().add(order1);
order1.setCustomer(customer0);
customer0.getOrders().add(order2);
order2.setCustomer(customer0);
return "OK";
}
private static String verifyInsert() {
Customer c =
findCustomer("Joe Smith");
Collection<Order>
orders = c.getOrders();
if (orders == null ||
orders.size() != 2) {
throw new RuntimeException("Unexpected number of orders: " + ((orders
== null) ? "null" : "" + orders.size()));
}
return "OK";
}
private static String testDelete(Customer c) {
// Merge the customer to the
new persistence context
Customer c0 = em.merge(c);
// Delete all records.
em.remove(c0);
return "OK";
}
private static String verifyDelete() {
Query q =
em.createQuery("select c from Customer c");
List results =
q.getResultList();
if (results == null ||
results.size() != 0) {
throw new RuntimeException("Unexpected number of customers after
delete");
}
q = em.createQuery("select o
from Order o");
results = q.getResultList();
if (results == null ||
results.size() != 0) {
throw new RuntimeException("Unexpected number of orders after delete");
}
return "OK";
}
private
static Customer findCustomer(String name) {
Query q = em.createQuery("select c from Customer c where c.name =
:name");
q.setParameter("name", name);
return (Customer) q.getSingleResult();
}
private
static void createTransactionalEntityManager() {
// Create a new EntityManager
em = emf.createEntityManager();
// Begin transaction
em.getTransaction().begin();
}
private
static void closeTransactionalEntityManager() {
// Commit the transaction
em.getTransaction().commit();
// Close this EntityManager
em.close();
}
private
static void createEntityManager() {
// Create a new EntityManager
em = emf.createEntityManager();
}
private
static void closeEntityManager() {
// Close this EntityManager
em.close();
}
}
|
Solution
The
solutions to
this exercise are provided as a ready-to-open-and-run
NetBeans projects as part of hands-on lab zip file.
- You can find CustomerHasManyOrders
project
as <LAB_UNZIPPED_DIRECTORY>/jpamapping/solutions/CustomerHasManyOrders.
Summary
In this exercise, you have learned how
to use inheritance strategies and how database tables are created
accordingly. You learned that, in SINGLE_TABLE strategy, a single
table gets created for the class hierarchy.
Exercise 2: Exercise Inheritance O/R
Mapping of JPA
There is a bug in NetBeans 6.1
that prevents this exercise to work as
described in the lab document below. This is fixed in NetBeans
6.5.
In this exercise, you are going to
exercise two inheritance strategies
SINGLE_TABLE
and
JOINED.
Under SINGLE_TABLE strategy, a single table is created per class
hierarchy. Under JOINED strategy, fields that are specific to a
subclass are mapped to a separate table than the fields that are common
to the parent class, and a join is performed to instantiate the
subclass.
The example
scenario we are going to use is
Person
class which has
name property
and
Student class which as
school and
grade properties. The Student class
is a subclass of the Person class.
- Use "SINGLE_TABLE" inheritance strategy implicitly
(as a default)
- Use "SINGLE_TABLE" inheritance strategy explicitly
(by using annotation)
- Use "JOINED" inheritance strategy
(2.1)
Use "SINGLE_TABLE" inheritance strategy implicitly (as a default)
In this step, you are going to use
SINGLE_TABLE
as a default
inheritance
strategy. The SINGLE_TABLE strategy is a default strategy, which
means,
in the absence of inheritance strategy annotation, SINGLE_TABLE
strategy is
used.
1. Create a NetBeans project.
- Select File->New Project (Ctrl+Shift+N).
- Observe that the New Project
dialog box appears.
- Under Choose Project
pane,
select Web under Categories and Web
Application under Projects.
- Click Next.
- Observe that the Name and
Location
pane appears.
- For Project Name field,
type in ORInheritanceSINGLE_TABLE.
(Figure-2.10 below)
- Click Next.

Figure-2.10: Create a new NetBeans project
- Observe that the Server and
Settings pane appears with default values.
- Click Next.
- Observe that the Frameworks
pane appears.
- Select JavaServer
Faces.
- Click Finish.
2. Create a Persistence Unit for the project.
- Right click ORInheritanceSINGLE_TABLE
project
and New->Other.
- Observe that the Choose File
Type pane appears.
- Select Persistence under
Categories and Persistence Unit under File Types.
- Observe that the Provider and
Database pane appears.
- For the Data Source
field, select jdbc/sample
from the drop-down menu.
- For the Table Generation
Strategy, select Drop and Create.
(Figure-2.13 below) Every time you are running the project,
existing tables will be dropped (removed) and new tables will be
created.
- Click Finish.

Figure-2.13: Provider and Database
3. Write
Person Entity class.
- Right click ORInheritanceSINGLE_TABLE
project
node and select Other.
- Select Persistence under
Categories and select Entity
Class
- Observe that the Name and
Location pane appears.
- For the Class Name
field, type in Person.
- For the Package
field, type in mypackage.
(Figure-2.14 below)
- Click Finish.

Figure-2.14: Name and Location
4. Add
name field to the
Person Entity class.
- Modify Person.java under
ORInheritanceSINGLE_TABLE->Source
Packages->mypackage as shown in Code-2.15 below. The
code fragment that needs to be added is highlighted in bold and red-colored
font.
package mypackage;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
*
* @author sang
*/
@Entity
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
private Long id;
// Add a name
field to the Person class
private String name;
public void setId(Long id) {
this.id = id;
}
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
public Long getId() {
return id;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ?
id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this
method won't work in the case the id fields are not set
if (!(object instanceof
Person)) {
return false;
}
Person other = (Person)
object;
if ((this.id == null
&& other.id != null) || (this.id != null &&
!this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return
"mypackage.Person[id=" + id + "]";
}
}
|
Code-2.15: Modified Person.java
5. Create getter and setter (accessor) methods of the
name field.
- Right click the name field in the
source editor and select Refactor->Encapsulate
Fields. (You can maximize or minimize a window by
double-clicking the tab of the file. For example, if you double click Person.java tab, it will maximize it
as shown below. In order to minimize it, double click it again.)
- Observe that Encapsulate Fields
- mypackage.Person dialog box appears. (Figure-2.16 below)
- Click Refactor.

Figure-2.16: Encapsulate Fields refactoring
- Observe now the Person class
has
getName() and setName()
methods at the end part of the code.
6. Write
Student Entity class
by extending
Person Entity
class.
- Right click ORInheritanceSINGLE_TABLE project
and select New->Java Class.
- Observe that the Name and
Location pane appears.
- For the Class Name
field, type in Student.
- For the Package field,
type in mypackage.
(Figure-2.18 below)
- Click Finish.

Figure-2.18: Student Java class
- Modify Student.java as
shown in Code-2.19 below. The code fragments that need to be
added are highlighted in bold and
blue-colored font. The change is to make the Student class to be Entity class
and also extends Person class.
package mypackage;
/**
*
* @author sang
*/
@Entity
public class Student extends Person {
}
|
Code-2.19: Modified Student.java
7. Do "
Fix Imports" for the
Student.java. (If you did code
completion by pressing CTRL+Space, you do not need to
do this step since NetBeans automatically adds the imports.)
- Observe that @Entity has
"Cannot find Symbol" compiler
error. This is because the Entity class has not be imported.
- Right click @Entity and
select Fix Imports.
(Figure-2.20 below)

Figure-2.20: Fix Imports
- Observe that the Fix Imports
dialog box appears.
- Select javax.persitence.Entity
from the drop-down menu. (Figure-2.21 below)
- Click OK.
- Observe that import statement is added and compiler error
disappears from the source editor.

Figure-2.21: Fix Imports
8. Add
school and
grade fields to the
Student.java
- Modify the Student.java
as shown in Code-2.22 below. The code fragments that need to be
changed are highlighted in bold and
blue-colored font.
package mypackage;
import javax.persistence.Entity;
/**
*
* @author sang
*/
@Entity
public class Student extends Person
implements Serializable {
String school;
double grade;
}
|
Code-2.22: Add fields to Student.java
9. Create getter and setter methods of the school and grade fields.
- Right click the school
field and select Refactor->Encapsulate
Fields.
- Observe that Encapsulate Fields
- mypackage.Student dialog box appears.
- Check all boxes and click Next.
(Figure-2.23 below)

Figure-2.23: Encapsulate both school and grade fields
10. Generate JavaServer Faces (JSF) pages from the Entity classes
- Right click ORInheritanceSINGLE_TABLE
project and select JSF
Pages from Entity Class.
- Observe that New JSF Pages from
Entity Class dialog box appears.
- Click Add All >>
and observe that Person and Student classes are moved to the Selected Entity Classes section on
the right. (Figure
- Click Next.

Figure-2.24: Select Entity classes for JSF page generation
- Observe that the Generated JSF
Pages and Classes pane appears.
- Accept all defaults and select Finish.
(Figure-2.25 below)

Figure-2.25: Generated JSF Pages and Classes
Trouble-shooting: If you are seeing a warning message
"mypackage.Student: Could not find Id property." as shown below, it is
because of a bug in NetBeans 6.1. This is fixed in NetBeans 6.5
Work-around with NetBeans 6.1:
On NetBeans 6.1, Make the Id field protected and duplicate getId method
in the Student class exactly as it appears in the Person class,
including the annotations. Then you can generate the JSF pages. Then
you can go back and edit the entities to be as they should.
package mypackage;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
*
* @author sang
*/
@Entity
public class Person implements Serializable {
private static final long serialVersionUID = 1L;
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
protected Long
id;
// Add a name field to the Person class
private String name;
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
@Override
public int hashCode() {
int hash = 0;
hash += (id != null ?
id.hashCode() : 0);
return hash;
}
@Override
public boolean equals(Object object) {
// TODO: Warning - this
method won't work in the case the id fields are not set
if (!(object instanceof
Person)) {
return false;
}
Person other = (Person)
object;
if ((this.id == null
&& other.id != null) || (this.id != null &&
!this.id.equals(other.id))) {
return false;
}
return true;
}
@Override
public String toString() {
return
"mypackage.Person[id=" + id + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
|
Person.java
package mypackage;
import javax.persistence.Entity;
/**
*
* @author sang
*/
@Entity
public class Student extends Person {
String school;
private double grade;
// Temporary work-around. Delete this after you create JSF pages.
protected Long id; // Add a name field to the Person
class
public Long getId() {
return id;
}
public void setId(Long id) {
this.id = id;
}
// End
public String getSchool() {
return school;
}
public void setSchool(String school) {
this.school = school;
}
public double getGrade() {
return grade;
}
public void setGrade(double grade) {
this.grade = grade;
}
}
|
Student.java
11. Build and run the application
- Right click ORInheritanceSINGLE_TABLE
project node and select Run.
- Observe the browser gets displayed as shown below.
- Click New Person.
(Figure-2.27 below)

Figure-2.27: Click New Person
- Observe that New person
page gets displayed.
- For the Name field,
type in your name (Sang Shin,
for example).
- Click Create.
(Figure-2.28 below)

Figure-2.28: Create a new Person
- Observe that Listing Persons
now has a new person.
- Click Back to index.

Figure-2.29: A person instance is created
13. Create a Student persistence
- Click List of Student.
(Figure-2.30 below)

Figure-2.30: Click List of Student.
- Observe Listing Students page gets displayed.
- Click New Student.
(Figure-2.31 below)

Figure-2.31: Click New Student.
- Observe that the New student page gets displayed.
- Enter values to the fields as shown in Figure-2.32 below.
- Click Create.

Figure-2.32: Create a student
- Observe that the Listing Students now has a new Student instance.
- Click New Student to
create another Student instance. (Figure-2.33 below)

Figure-2.33: Listing Students.
- Observe that New student
page is displayed.
- Enter values to the fields as shown in Figure-2.34 and click Create.

Figure-2.34: Create a second student
- Observe that the Listing Students page gets displayed with 2
students now. (Figure-2.35 below).

Figure-2.35: Listing Students
10. Verify the database table that is created.
In this step, you are going to verify the database table that is
created. Since the default strategy is SINGLE_TABLE, the PERSON
database table should be the only table that gets generated and it
should contain all the fields of both Person and Student Entity classes
- name, school, and grade.
- Select Runtime tab of
the NetBeans IDE.
- Expand Databases.
- Right click jdbc:derby://localhost:1527/sample
[app on APP] and
select Connect.
(Figure-1.10 above)
- Observe that Connect
dialog box appears
- For the Password field,
type in app.
(Figure-1.11 above)
- Expand jdbc:derby://localhost:1527/sample
[app on APP].
- Expand Tables
- Observe that PERSON table is now created.
(If the Tables is already expanded and if you don see PERSON table,
right click Tables and select Refresh.)
- Right click PERSON table and select View Data.
- Observe that single PERSON table contains 3 rows. Also
observe that the DTYPE column
indicates which Entity the row represents.

Figure-2.37: PERSON database table
- Right click PERSON database
table and select Delete.
(This
is for the subsequent exercise.)
return to top of
the exercise
(2.2)
Use SINGLE_TABLE as
inheritance strategy explicitly
In this step, you are going to use SINGLE_TABLE strategy by explicitly
specifying it. The behavior of the application should be
the
same as you've seen in Exercise 4.1 because SINGLE_TABLE strategy is
the default.
1. Modify
Person.java to
specify
SINGLE_TABLE strategy
explicitly as shown in Code-2.20 below. The code fragment that
needs to be added is high-lighted in
bold and
blue-colored font. This is to specify the
SINGLE_TABLE
explicitly as inheritance strategy.
package mypackage;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* Entity class Person
*
* @author sang
*/
@Entity
@Inheritance(strategy=InheritanceType.SINGLE_TABLE)
public class Person implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
// Add a name field to the Person class
private String name;
/** Creates a new instance of Person */
public Person() {
}
/**
* Gets the id of this Person.
* @return the id
*/
public Long getId() {
return this.id;
}
/**
* Sets the id of this Person to the specified
value.
* @param id the new id
*/
public void setId(Long id) {
this.id = id;
}
/**
* Returns a hash code value for the
object. This implementation computes
* a hash code value based on the id fields in
this object.
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
int hash = 0;
hash += (this.id != null ?
this.id.hashCode() : 0);
return hash;
}
/**
* Determines whether another object is equal
to this Person. The result is
* <code>true</code> if and only if
the argument is not null and is a Person object that
* has the same id field values as this object.
* @param object the reference object with
which to compare
* @return <code>true</code> if
this object is the same as the argument;
* <code>false</code> otherwise.
*/
@Override
public boolean equals(Object object) {
// TODO: Warning - this
method won't work in the case the id fields are not set
if (!(object instanceof
Person)) {
return false;
}
Person other =
(Person)object;
if (this.id != other.id
&& (this.id == null || !this.id.equals(other.id))) return false;
return true;
}
/**
* Returns a string representation of the
object. This implementation constructs
* that representation based on the id fields.
* @return a string representation of the
object.
*/
@Override
public String toString() {
return
"mypackage.Person[id=" + id + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
|
Code-2.20: Use SINGLE_TABLE strategy explicitly
<NetBeans Tip>
You might want to take advantage of the code-completion feature of
NetBeans IDE on annotations.
- For example, just type @Inh
and press CTRL+SPACE and observe that two possible annotations that
start with @Inh - @Inheritance and @Inherited - are displayed.
- Choose @Inheritance.
(Figure-2.21 below)
Figure-2.21: Code completion on @Inheritance
- Press CTRL+SPACE again.
- Choose InheritanceType strategy.
(Figure-2.22 below)

Figure-2.22: Code completion on strategy=
- Press CTRL+SPACE and observe that possible inheritance strategies
are displayed.
- Choose SINGLE_TABLE.
(Figure-2.23 below)

Figure-2.23: Code completion on SINGLE_TABLE
- Observe that @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
is completed
2. Right click the newly added line and select
Fix Imports. (If you did code
completion by pressing CTRL+Space, you do not need to
do this step since NetBeans automatically adds the imports.)
3. See JavaDoc of the SINGLE_TABLE inheritance strategy.
- Right click on the @Inheritance(strategy=InheritanceType.SINGLE_TABLE)
and choose Show Javadoc.
(Figure-2.25 below)

Figure-2.25: Show Javadoc
- Observe that the browser shows the Javadoc of the Enum InheritanceType.
- Observe the description of SINGLE_TABLE
and JOINED. (Figure-2.26
below)

Figure-2.26: Javadoc of SINGLE_TABLE and JOINED
4. Run the application
- Right click ORInheritanceSINGLE_TABLE
project and select Run.
- Create a couple of Person instances and a couple of Student
instances as you did in Exercise 1, Step 9.
4. Verify the database table that is created.
6. Right click
PERSON database
table and select
Delete.
(This
is for the subsequent exercise.)
return to top of
the exercise
(2.3)
Use JOINED inheritance strategy explicitly
In this step, you are going to use
JOINED
inheritance strategy.
You are going to follow similar steps you've done in step 4.2
above. Just to avoid some confusion, we are going to name the two
classes as Person2 and Student2.
In JOINED strategy, fields that are specific to a subclass are mapped
to a separate table than the fields that are common to the parent
class, and a join is performed to instantiate the subclass.
1. Create a NetBeans project. (Same step as in 4.2 above)
- Select File->New Project (Ctrl+Shift+N). The New Project dialog box appears.
- Under Choose Project
pane,
select Web under Categories and Web
Application under Projects.
Click Next.
- Observe Name and Location
pane appears.
- For Project Name field,
type in ORInheritanceJOINED.
- Click Next.
- Observe that the Frameworks
pane appears.
- Select JavaServer
Faces.
- Click Finish.
2. Create a Persistence Unit for the project. (Same step as in
4.2 above)
- Right click ORInheritanceJOINED
project
and select New->Persistence Unit.
- Observe that the Provider and
Database pane appears.
- For the Data Source
field, select jdbc/sample
from the drop-down menu.
- For the Table Generation
Strategy, select Drop and Create.
Every time you are running the project,
existing tables will be dropped (removed) and new tables will be
created.
- Click Finish.
3. Write
Person2 Entity
class. (Same step as in 4.2 above)
- Right click ORInheritanceJOINED
project
and select New->Entity Class
- Observe that the Name and
Location pane appears.
- For the Class Name
field, type in Person2.
- For the Package
field, type in mypackage.
- Click Finish.
4. Add
name field to the
Person2 Entity class. (Same step as
in 4.2 above)
- Modify Person2.java
under ORInheritanceJOINED->Source
Packages->mypackage as shown in Code-2.15 above.
- Right click the name field in the
source editor and select Refactor->Encapsulate
Fields.
- Observe that Encapsulate Fields
- mypackage.Person dialog box appears.
- Click Next.
- Observe that Output area
has refactor preview.
- Click Do Refactoring to
confirm the refactoring.
- Observe now the Person class has
getName() and setName()
methods at the end part of the code.
5. Write
Student2 Entity
class
by extending
Person2 Entity
class.
- Right click ORInheritanceJOINED project
and select New->Java Class.
- Observe that the Name and
Location pane appears.
- For the Class Name
field, type in Student2.
- For the Package field,
type in mypackage.
- Click Finish.
- Modify Student2.java as
shown in Code-2.62 below. The code fragments that need to
modified are high lighted in bold and
blue-colored font.
package mypacakge;
/**
*
* @author sang
*/
@Entity
public class Student2 extends Person2
{
/** Creates a new instance of Student2 */
public Student2() {
}
}
|
Code-2.62: Modified Student2.java
6. Do "
Fix Imports" for the
Student2.java. (If you did code
completion by pressing CTRL+Space, you do not need to
do this step since NetBeans automatically adds the imports.)
- Observe that @Entity has
"Cannot find Symbol" compiler error.
- Right click @Entity and
select Fix Imports.
- Observe that the Fix Imports
dialog box appears.
- Select javax.persitence.Entity
from the drop-down menu.
- Click OK.
- Observe that import statement is added and compiler error
disappears from the source editor.
7. Add
school and
grade fields to the Student2.java
- Modify the Student2.java
as shown in Code-2.63 below. The code fragments that need to modified
are high lighted in bold and
blue-colored font.
package mypacakge;
import javax.persistence.Entity;
/**
*
* @author sang
*/
@Entity
public class Student2 extends Person2 {
String school;
double grade;
/** Creates a new instance of Student2 */
public Student2() {
}
}
|
Code-2.63: Modified Student2.java
- Right click the school
field and select Refactor->Encapsulate
Fields.
- Observe that Encapsulate Fields
- mypackage.Student2 dialog box appears.
- Check all boxes and click Next.
- Observe that Output area
has refactor preview.
- Click Do Refactoring to
confirm the refactoring.
- Observe now the getSchool()/setSchool()
and getGrade()/setGrade()
methods are added at the end part of the code.
8. Use JOINED inheritance strategy.
- Modify the Person2.java
as shown Code-2.64 below. The code fragment that needs to be
added is high lighted in bold and
blue-colored font.
- Right click the newly added line and select Fix Imports. (If you did code
completion by pressing CTRL+Space, you do not need to
do this step since NetBeans automatically adds the imports.)
package mypacakge;
import java.io.Serializable;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
/**
* Entity class Person2
*
* @author sang
*/
@Entity
@Inheritance(strategy=InheritanceType.JOINED)
public class Person2 implements Serializable {
@Id
@GeneratedValue(strategy = GenerationType.AUTO)
private Long id;
private String name;
/** Creates a new instance of Person2 */
public Person2() {
}
/**
* Gets the id of this Person2.
* @return the id
*/
public Long getId() {
return this.id;
}
/**
* Sets the id of this Person2 to the specified
value.
* @param id the new id
*/
public void setId(Long id) {
this.id = id;
}
/**
* Returns a hash code value for the
object. This implementation computes
* a hash code value based on the id fields in
this object.
* @return a hash code value for this object.
*/
@Override
public int hashCode() {
int hash = 0;
hash += (this.id != null ?
this.id.hashCode() : 0);
return hash;
}
/**
* Determines whether another object is equal
to this Person2. The result is
* <code>true</code> if and only if
the argument is not null and is a Person2 object that
* has the same id field values as this object.
* @param object the reference object with
which to compare
* @return <code>true</code> if
this object is the same as the argument;
* <code>false</code> otherwise.
*/
@Override
public boolean equals(Object object) {
// TODO: Warning - this
method won't work in the case the id fields are not set
if (!(object instanceof
Person2)) {
return false;
}
Person2 other =
(Person2)object;
if (this.id != other.id
&& (this.id == null || !this.id.equals(other.id))) return false;
return true;
}
/**
* Returns a string representation of the
object. This implementation constructs
* that representation based on the id fields.
* @return a string representation of the
object.
*/
@Override
public String toString() {
return
"mypacakge.Person2[id=" + id + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
|
Code-2.64: Use JOINED inheritance strategy
9. Generate JavaServer Faces (JSF) pages from the Entity classes
- Right click ORInheritanceJOINED
project and select JSF
Pages from Entity Class.
- Observe that New JSF Pages from
Entity Class dialog box appears.
- Click Add All >>
and observe that Person2 and Student2 classes are moved to the Selected Entity Classes section on
the right.
- Click Next.
- Observe that the Generated JSF
Pages and Classes pane appears.
- Accept all defaults and select Finish.
10. Run the application
- Right click ORInheritanceJOINED
project and select Run.
- Observe that browser gets displayed.
- Add a couple of Person2 instances
and a couple of Student2 instances.
11. Verify the database tables that are created.
In this step, you are going to verify the database table that is
created. In JOINED strategy, there should be
two tables, PERSON table for maintaining common data fields in the
hierarchy and STUDENT table for maintaining only fields that are
specific to the Student Entity.
- Expand jdbc:derby://localhost:1527/sample
[app on APP].
- Expand Tables.
(If Tables is already expanded, right click it and select Refresh)
- Observe that PERSON2 and STUDENT2 tables are now created.
- Right click PERSON2 table and select View Data. Note that it has
only NAME column.
(Figure-2.65 below)

Figure-2.65: PERSON2 table
- Right click STUDENT2 table and select View Data.
- Observe that it has SCHOOL and GRADE columns. (Figure-2.66 below)

Solution
The
solutions to
this exercise are provided as a ready-to-open-and-run
NetBeans projects as part of hands-on lab zip file.
- You can find ORInheritanceSINGLE_TABLE
project
as <LAB_UNZIPPED_DIRECTORY>/jpamapping/solutions/ORInheritanceSINGLE_TABLE.
- You can find ORInheritanceJOINED
project as <LAB_UNZIPPED_DIRECTORY>/jpamapping/solutions/ORInheritanceJOINED.
Summary
In this exercise, you have learned how
to use inheritance strategies and how database tables are created
accordingly. You learned that, in SINGLE_TABLE strategy, a single
table gets created for the class hierarchy.
return
to the top
Homework
Exercise (for people
who
are taking Sang Shin's "Java EE Programming online course")
There
is a bug in NetBeans 6.1 that prevents this exercise to work as
described in the lab document. This is fixed in NetBeans
6.5. Given that most people are using NetBeans 6.1 for now, I am
waiving the homework.
1.
The homework is to modify the ORInheritanceJOINED project as described below. (You
might want to create a new project by copying
the ORInheritanceJOINED
project. You can name
the
homework project in any way you want
but here I am going to call it MyORInheritanceJOINED.)
- Add another subclass called Teacher2
to the Person2 Entity
class.
- Add the following two fields to the Teacher2 class.
- String subjectToTeach // Subject
he or she teaches
- int
years
// Number of years he or she have taught
2
. Send the following files to
j2eehomeworks@sun.com
with Subject
as J2EEHomework-jpamapping.
- Zip file of the the
MyORInheritanceJOINED
NetBeans project. (Someone else
should be able to open and run it as a NetBeans project.) You can
use your favorite zip utility or you can use "jar" utility that comes
with JDK as following.
- cd <parent directory that contains MyORInheritanceJOINED directory>
(assuming you named your project as MyORInheritanceJOINED)
- jar cvf MyORInheritanceJOINED.zip MyORInheritanceJOINED (MyORInheritanceJOINED should
contain nbproject directory)
- Captured output screen -
name it as J2EEHomework-jpamapping.gif
orJ2EEHomework-jpamapping.jpg (or J2EEHomework-jpamapping.<whatver
graphics format>)
- Any screen capture that shows that your program is working is
good enough.
- If you decide to use
different IDE other than NetBeans, the zip
file should contain all the files that are needed for rebuilding the
project - war file with necessary source files is OK.