Introduction, Using, Developing Java Persistence API (JPA) 2.0 using EclipseLink, Derby, MySql and Eclipse

The article is written for/using J2SE 6, Java Persistence API (JPA) 2.0, EclipseLink 1.1.2, Derby 10.5.1.1, MySQL 5.1.37 GA, and Eclipse IDE for Java EE Developers [Ganymede].



Table of Content

  1. Introduction
  2. System Requirements
  3. Article Prerequisites
  4. JPA Specification
  5. New Features in JPA 2.0
  6. Java Persistence API (JPA) Architecture
  7. ORM Frameworks
  8. JPA Annotations
  9. Persistence Units
  10. Setup JPA, EclipseLink and Database
  11. Creating JPA Entities, Persistence XML and Storing Data to DB
  12. Creating and Using Custom EntityManagerFactory
  13. Running JUnit TestCase for JPA
  14. Summary
  15. Resources
  16. Feedback



Introduction

This article explains Java Persistence API (JPA) and how to use EclipseLink, the reference implementation for the Java Persistence API (JPA). The usage of EclipseLink is demonstrated for stand-aloneJava applications (outside the Java EE environment).



System Requirements

To follow along and try out the code for this tutorial, you need a working installation of either:

The instructions and examples in the tutorial are based on a Microsoft® Windows® operating system. All the tools covered in the tutorial also work on Linux® and UNIX® systems.



Article Prerequisites

To get the most from this tutorial, you should be familiar with Java syntax and the basic concepts of object-oriented development on the Java platform.

To setup MySQL and/or Derby database with eclipse, you can go through the following articles:



JPA Specification

All classes and annotations of this API are in the javax.persistence package. The main components of JPA are as follows:

  • Object-Relational Mapping (ORM), which is the mechanism to map objects to data stored in a relational database.
  • An entity manager API to perform database-related operations, such as Create, Read, Update, Delete (CRUD) operations. This API allows you to avoid using the JDBC API directly.
  • The Java Persistence Query Language (JPQL), which allows you to retrieve data with an object-oriented query language.
  • Transactions and locking mechanisms when accessing data concurrently provided by Java Transaction API (JTA). Resource-local (non-JTA) transactions are also supported by JPA.
  • Callback and listeners to hook business logic into the life cycle of a persistent object.



New Features in JPA 2.0

This second version brings new APIs, extends JPQL, and adds these new functionalities:

  • Collections of simple data types (String, Integer, etc.) and of embeddable objects can now be mapped in separate tables. Previously, you could only map collections of entities.
  • Map support has been extended so that maps can have keys and values of basic types, entities, or embeddables.
  • Maintaining a persistent ordering is now possible with the @OrderColumn annotation.
  • Orphan removal allows child objects to be removed from a relationship if the parent object is removed.
  • Optimistic locking was already supported, but now pessimistic locking has been introduced.
  • A brand-new Query Definition API has been introduced to allow queries to be constructed in an object-oriented manner.
  • JPQL syntax is richer (e.g., it now allows case expressions).
  • Embeddable objects can now be nested into other embeddable objects and have relationships to entities.
  • The dot (.) navigation syntax has been extended to handle embeddables with relationships and embeddables of embeddables.
  • Support for a new caching API has been added.



Java Persistence API (JPA) Architecture

The diagram below illustrates the relationships between the primary components of the JPA architecture.

  • Persistence
  • The javax.persistence.Persistence class contains static helper methods to obtain EntityManagerFactory instances in a vendor-neutral fashion.

  • EntityManagerFactory
  • The javax.persistence.EntityManagerFactory class is a factory for EntityManagers.

  • EntityManager
  • The javax.persistence.EntityManager is the primary JPA interface used by applications. Each EntityManager manages a set of persistent objects, and has APIs to insert new objects and delete existing ones. When used outside the container, there is a one-to-one relationship between an EntityManager and an EntityTransaction. EntityManagers also act as factories for Query instances.

  • Entity
  • Entites are persistent objects that represent datastore records.

  • EntityTransaction
  • Each EntityManager has a one-to-one relation with a single javax.persistence.EntityTransaction. EntityTransactions allow operations on persistent data to be grouped into units of work that either completely succeed or completely fail, leaving the datastore in its original state. These all-or-nothing operations are important for maintaining data integrity.

  • Query
  • The javax.persistence.Query interface is implemented by each JPA vendor to find persistent objects that meet certain criteria. JPA standardizes support for queries using both the Java Persistence Query Language (JPQL) and the Structured Query Language (SQL). You obtain Query instances from an EntityManager.

The diagram above depicts the JPA exception architecture. All exceptions are unchecked. JPA uses standard exceptions where appropriate, most notably IllegalArgumentExceptions and IllegalStateExceptions. The specification also provides a few JPA-specific exceptions in the javax.persistence package.



ORM Frameworks

  • EclipseLink 1.1.2 [Formerly Toplink from oracle]
  • EclipseLink 1.1.2 is an open source implementation of JPA 2.0. EclipseLink is a JPA implementation, but it also supports XML persistence through Java XML Binding (JAXB) and other means such as Service Data Objects (SDO). It provides support not only for ORM, but also for object XML mapping (OXM), object persistence to Enterprise Information Systems (EIS) using Java EE Connector Architecture (JCA), and database web services.EclipseLink’s origins stem from the Oracle TopLink product given to the Eclipse Foundation in 2006.

  • Hibernate
  • iBatis
  • Open JPA



JPA Annotations

Object-Relational Mapping metadata enables the persistence provider to recognize an entity and to interpret the mapping. This metadata can be written in two different formats:

  • Annotations
  • The code of the entity is directly annotated with all sorts of annotations that are described in the javax.persistence package.

  • XML descriptors
  • Instead of (or in addition to) annotations, you can use XML descriptors. The mapping is defined in an external XML file that will be deployed with the entities.

Some JPA annotations:

  • @Entity
  • Informs the persistence provider that this class is an entity and that it should manage it. The entity class must be annotated with @javax.persistence.Entity (or denoted in the XML descriptor as an entity). The entity class must have a no-arg constructor that has to be public or protected. The entity class may have other constructors as well. The entity class must be a top-level class. An enum or interface cannot be designated as an entity. The entity class must not be final. No methods or persistent instance variables of the entity class may be final. The entity class must implement the Serializable interface. The instances of the class will be a row in the table. All entities must have a primary key. Keys can be a single field or a combination of fields.

    @Entity
    public class Book {
    

  • @Table
  • The @javax.persistence.Table annotation makes it possible to change the default values related to the table. You can specify the name of the table in which the data will be stored, the catalog, and the database schema. If this annotation is omitted, the name of the table will be the name of the entity.

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

  • @SecondaryTable, @SecondaryTables
  • Sometimes you need to spread the data across multiple tables. You can use @SecondaryTable to associate a secondary table to an entity or @SecondaryTables (with an “s”) for several secondary tables.

    @Entity
    @Table(name = "t_address")
    @SecondaryTables({
    @SecondaryTable(name = "t_city"),
    @SecondaryTable(name = "t_country")
    })
    public class Address {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String street1;
    private String street2;
    
    @Column(table = "city")
    private String city;
    @Column(table = "city")
    private String state;
    @Column(table = "city")
    private String zipcode;
    
    @Column(table = "country")
    private String country;
    

  • @Id
  • The @javax.persistence.Id annotation denotes a primary key. It can be one of the following types:

    • Primitive Java types: byte, int, short, long, char
    • Wrapper classes of primitive Java types: Byte, Integer, Short, Long, Character
    • Arrays of primitive or wrapper types: int[], Integer[], etc.
    • Strings, numbers, and dates: java.lang.String, java.math.BigInteger, java.util.Date, java.sql.Date
  • @GeneratedValue
  • This annotation can have four possible values to defind that value will be generated by application manually or automatically by persistence provider.

    • SEQUENCE
    • IDENTITY
    • TABLE
    • AUTO
  • @Basic
  • The @javax.persistence.Basic annotation overrides basic persistence options.

    @Entity
    public class Photo {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String phototitle;
    @Basic(fetch = FetchType.LAZY)
    @Lob
    private byte[] jpg;
    @Basic(fetch = FetchType.EAGER)
    @Lob
    private byte[] png;
    @Basic(optional = true)
    private String description;
    

  • @Column
  • The @javax.persistence.Column annotation defines the properties of a column.

    @Entity
    public class Photo {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    @Column(name = "photo_title", nullable = false, updatable = false)
    private String phototitle;
    @Column(length = 2000)
    private String description;
    

  • @Temporal
  • You can use the @javax.persistence.Temporal annotation to store date and time. This has three possible values: DATE, TIME, or TIMESTAMP.

    @Entity
    public class Person {
    @Id
    @GeneratedValue(strategy = GenerationType.AUTO)
    private Long id;
    private String name;
    @Temporal(TemporalType.DATE)
    private Date dateOfBirth;
    @Transient
    private Integer age;
    @Temporal(TemporalType.TIMESTAMP)
    private Date recordCreationDate;
    

  • @Transient
  • If you do not need to map an attribute to table, you can use the @javax.persistence.Transient annotation.

  • @Enumerated
  • This annotation is used to store the value of the enumerated type in the database.

    public enum CreditCardType {
    VISA,
    MASTER_CARD,
    AMERICAN_EXPRESS
    }
    

    @Entity
    public class CreditCard {
    @Id
    private String number;
    @Enumerated(EnumType.STRING)
    private CreditCardType creditCardType;
    

  • @ElementCollection, @CollectionTable, @MapKeyColumn
  • The @ElementCollection annotation is used to indicate that an attribute of type java.util.Collection contains Java types.
    The @CollectionTable annotation allows you to customize details of the collection table such as its name.
    The @MapKeyColumn annotation is used to specify the mapping for the key column of the map.

    @Entity
    public class Music {
    @Id
    @GeneratedValue
    private Long id;
    private String title;
    private String description;
    
    @ElementCollection
    @CollectionTable(name="Track")
    @MapKeyColumn (name = "Position")
    @Column(name = "Title")
    private Map<Integer, String> tracks;
    
    @ElementCollection(fetch = FetchType.LAZY)
    @CollectionTable(name = "Tag")
    @Column(name = "Value")
    private ArrayList<String> tags;
    

  • @NamedQuery, @NamedQueries
  • The @NamedQuery annotation defines a named query that uses JPQL to retrieve all the data from the database. Named queries are static and unchangeable.

    @Entity
    @NamedQuery(name = "findAll", query="SELECT c FROM Customer c")
    public class Customer {
    

    @Entity
    @NamedQueries({
    @NamedQuery(name = "findAll", query="select c from Customer c"),
    @NamedQuery(name = "findBhavesh", query="select c from Customer c where c.firstName = 'Bhavesh'"),
    @NamedQuery(name = "findWithParam", query="select c from Customer c where c.firstName = :fname")
    })
    public class Customer {
    

  • @OneToOne, @OneToMany, @ManyToOne, @ManyToMany
  • Database relationships can be one-sided, meaning that only one entity knows about the other entity or entities in the relationship. Unidirectional relationships have an “owning” side, the side that maintains the relationship in the database.
    Bidirectional relationships have both an owning and an “inverse” side. The owning side determines how and when updates affect the relationship. Also, the owning side usually contains the foreign key to the other entity.



Persistence Units

The set of entities in your application is called a persistence unit. You must define your application’s persistence unit in a configuration file called persistence.xml. This file should exist alongside your application in a META-INF directory. You can put the META-INF subdirectory within your project’s source directory. The persistence.xml file’s important task is to list all the entities in your application and to name the persistence unit. The important elements of persistence.xml are the following:

  • persistence-unit
  • The persistence-unit’s name attribute can be anything you choose. In Java SE applications, the default transaction type is RESOURCE-LOCAL. In Java EE environments, the transaction type is JTA, which means that the entity manager participates in the transaction.

  • provider
  • The provider element declares the class file that provides the initial factory for creating an EntityManager instance.

  • class
  • Use the class element to list the entity class names in your application.

  • property
  • You should put database connection properties. You can include persistence provider properties like options to create or drop-create new tables.



Setup JPA, EclipseLink and Database

To setup/install/configure Derby Database or MySQL Database with Eclipse follow below articles on this same blog.

Now lets setup EclipseLink 1.1.2. Extract eclipselink-[version].zip. Now copy jars from eclipselink -> jlib -> jpa, eclipselink -> jlib -> moxy, and eclipselink -> jlib -> sdo to eclipselink -> jlib. Your eclipselink directory should look like as under:

Now you need to setup User Library for EclipseLink 1.1.2 in Eclipse. In Eclipse, select Window -> Preferences -> JPA. Click Configure User Libraries…. Click New… and give name EclipseLink 1.1.2 and press OK. Click Add JARs…. Browse location where you have extracted EclipseLink and select all JARs from eclipselink -> jlib. Now goto Preferences -> JPA and from drop down select EclipseLink 1.1.2. Press OK.



Creating JPA Entities, Persistence XML and Storing Data to DB

To get started we will create a simple JPA Project by selecting New > JPA Project from the File menu. Alternatively, invoke the wizard using File > New > JPA Project.

Name the project JPAEclipseLinkDemo and select Target Runtime as Apache Tomcat v6.0. If Target Runtime is not set, leave it None. select Configuration as Default Configuration. Click Next >.

On JPA Facet dialog box, select Platform as EclipseLink. Select Connection as MyDerbyConnection. Alternatively if you have configured MYSQL or any other Database, select that connection. Select JPA Implementation -> Use Implementation Library as EclipseLink 1.1.2. Check Create orm.xml checkbox. Click Finish. You will be asked to open JPA Perspective. Select Yes.

NOTE: It is not required to set Target Runtime.

Use the File > New > Other > JPA > Entity wizard. Click Next >. On New JPA Entity -> Entity class dialog box, put Job in the Class Name field, edu.bhavesh.jpa.eclipselink.model in the Package field and click Next >.

On New JPA Entity -> Entity Properties dialog box, click Add… to add entities. Click Finish to finish the wizard.

Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
* Entity implementation class for Entity: Job
* 
* @author Bhavesh.Thaker
* 
*/
@Entity
public class Job implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private int id;
private double salary;
private String jobDescription;
@Temporal(TemporalType.TIMESTAMP)
private java.util.Calendar creationDate = java.util.Calendar.getInstance();
private static final long serialVersionUID = 1L;

public Job() {
super();
}

public int getId() {
return this.id;
}

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

public double getSalary() {
return this.salary;
}

public void setSalary(double salary) {
this.salary = salary;
}

public String getJobDescription() {
return this.jobDescription;
}

public void setJobDescription(String jobDescription) {
this.jobDescription = jobDescription;
}

public java.util.Calendar getCreationDate() {
return creationDate;
}

public void setCreationDate(java.util.Calendar creationDate) {
this.creationDate = creationDate;
}
}

Use the File > New > Other > JPA > Entity wizard. Click Next >. On New JPA Entity -> Entity class dialog box, put Address in the Class Name field, edu.bhavesh.jpa.eclipselink.model in the Package field and click Next >. On New JPA Entity -> Entity Properties dialog box, click Add… to add entities. Click Finish to finish the wizard. Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink.model;

import java.io.Serializable;

import javax.persistence.Column;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.SecondaryTable;
import javax.persistence.SecondaryTables;
import javax.persistence.Table;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
* Entity implementation class for Entity: Address
* 
* @author Bhavesh.Thaker
* 
*/
@Entity
@Table(name = "t_address")
@SecondaryTables( { @SecondaryTable(name = "t_city"),
@SecondaryTable(name = "t_country") })
public class Address implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private Long id;
private String street1;
private String street2;
@Column(table = "t_city")
private String city;
@Column(table = "t_city")
private String state;
@Column(table = "t_city")
private String zipcode;
@Column(table = "t_country")
private String country;
@Temporal(TemporalType.TIMESTAMP)
private java.util.Calendar creationDate = java.util.Calendar.getInstance();

private static final long serialVersionUID = 1L;

public Address() {
super();
}

public Long getId() {
return id;
}

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

public String getStreet1() {
return street1;
}

public void setStreet1(String street1) {
this.street1 = street1;
}

public String getStreet2() {
return street2;
}

public void setStreet2(String street2) {
this.street2 = street2;
}

public String getCity() {
return city;
}

public void setCity(String city) {
this.city = city;
}

public String getState() {
return state;
}

public void setState(String state) {
this.state = state;
}

public String getZipcode() {
return zipcode;
}

public void setZipcode(String zipcode) {
this.zipcode = zipcode;
}

public String getCountry() {
return country;
}

public void setCountry(String country) {
this.country = country;
}

public java.util.Calendar getCreationDate() {
return creationDate;
}

public void setCreationDate(java.util.Calendar creationDate) {
this.creationDate = creationDate;
}
}

Use the File > New > Other > Java > Enum wizard. Click Next >. On Enum Type dialog box, put CreditCardType in the Class Name field, edu.bhavesh.jpa.eclipselink.model in the Package field and click Finish. Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink.model;

/**
* @author Bhavesh.Thaker
* 
*/
public enum CreditCardType {
VISA, MASTER_CARD, AMERICAN_EXPRESS
}

Use the File > New > Other > JPA > Entity wizard. Click Next >. On New JPA Entity -> Entity class dialog box, put Person in the Class Name field, edu.bhavesh.jpa.eclipselink.model in the Package field and click Next >. On New JPA Entity -> Entity Properties dialog box, click Add… to add entities. Click Finish to finish the wizard. Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.EnumType;
import javax.persistence.Enumerated;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;
import javax.persistence.Transient;

/**
* Entity implementation class for Entity: Person
* 
* @author Bhavesh.Thaker
* 
*/
@Entity
public class Person implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private String id;
private String firstName;
private String lastName;
@Temporal(TemporalType.DATE)
private java.util.Calendar dateOfBirth;
@Transient
private String age = "";
@Enumerated(EnumType.STRING)
private CreditCardType creditCardType;
@ManyToOne
private Family family;
@ManyToOne
private Address address;
@OneToMany
private java.util.List<Job> jobList = new java.util.ArrayList<Job>();
@Temporal(TemporalType.TIMESTAMP)
private java.util.Calendar creationDate = java.util.Calendar.getInstance();
private static final long serialVersionUID = 1L;

public Person() {
super();
}

public String getId() {
return this.id;
}

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

public String getFirstName() {
return this.firstName;
}

public void setFirstName(String firstName) {
this.firstName = firstName;
}

public String getLastName() {
return this.lastName;
}

public void setLastName(String lastName) {
this.lastName = lastName;
}

public String getAge() {
return this.age;
}

public void setAge(String age) {
this.age = age;
}

public Family getFamily() {
return this.family;
}

public void setFamily(Family family) {
this.family = family;
}

public java.util.List<Job> getJobList() {
return this.jobList;
}

public void setJobList(java.util.List<Job> jobList) {
this.jobList = jobList;
}

public Address getAddress() {
return address;
}

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

public java.util.Calendar getDateOfBirth() {
return dateOfBirth;
}

public void setDateOfBirth(java.util.Calendar dateOfBirth) {
this.dateOfBirth = dateOfBirth;
}

public CreditCardType getCreditCardType() {
return creditCardType;
}

public void setCreditCardType(CreditCardType creditCardType) {
this.creditCardType = creditCardType;
}

public java.util.Calendar getCreationDate() {
return creationDate;
}

public void setCreationDate(java.util.Calendar creationDate) {
this.creationDate = creationDate;
}
}

Use the File > New > Other > JPA > Entity wizard. Click Next >. On New JPA Entity -> Entity class dialog box, put Family in the Class Name field, edu.bhavesh.jpa.eclipselink.model in the Package field and click Next >. On New JPA Entity -> Entity Properties dialog box, click Add… to add entities. Click Finish to finish the wizard. Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink.model;

import java.io.Serializable;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.OneToMany;
import javax.persistence.Temporal;
import javax.persistence.TemporalType;

/**
* Entity implementation class for Entity: Family
* 
* @author Bhavesh.Thaker
* 
*/
@Entity
public class Family implements Serializable {

@Id
@GeneratedValue(strategy = GenerationType.TABLE)
private int id;
private String description;
@OneToMany(mappedBy = "family")
private java.util.List<Person> members = new java.util.ArrayList<Person>();
@Temporal(TemporalType.TIMESTAMP)
private java.util.Calendar creationDate = java.util.Calendar.getInstance();

private static final long serialVersionUID = 1L;

public Family() {
super();
}

public int getId() {
return this.id;
}

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

public String getDescription() {
return this.description;
}

public void setDescription(String description) {
this.description = description;
}

public java.util.List<Person> getMembers() {
return members;
}

public java.util.Calendar getCreationDate() {
return creationDate;
}

public void setCreationDate(java.util.Calendar creationDate) {
this.creationDate = creationDate;
}

public void setMembers(java.util.List<Person> members) {
this.members = members;
}
}

Now we have our entities ready. Next step is to create persistence.xml. persistence.xml is created under META-INF directory when you created project. Replace the contents of the generated xml with the following code:

<?xml version="1.0" encoding="UTF-8"?>
<persistence xmlns="http://java.sun.com/xml/ns/persistence"
version="1.0">
<persistence-unit name="JPAEclipseLinkDemoPU"
transaction-type="RESOURCE_LOCAL">
<provider>org.eclipse.persistence.jpa.PersistenceProvider
</provider>
<class>edu.bhavesh.jpa.eclipselink.model.Family
</class>
<class>edu.bhavesh.jpa.eclipselink.model.Person
</class>
<class>edu.bhavesh.jpa.eclipselink.model.Job
</class>
<class>edu.bhavesh.jpa.eclipselink.model.Address
</class>
<properties>
<property name="eclipselink.target-database" value="DERBY" />
<property name="eclipselink.jdbc.driver" value="org.apache.derby.jdbc.EmbeddedDriver" />
<property name="eclipselink.jdbc.url"
value="jdbc:derby:C:\eclipse\workspace\MyDerbyDB;create=true;upgrade=true" />
<property name="eclipselink.jdbc.user" value="admin" />
<property name="eclipselink.jdbc.password" value="password" />
<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.logging.level" value="INFO" />
<property name="eclipselink.logging.logger" value="JavaLogger"></property>
<property name="eclipselink.ddl-generation" value="drop-and-create-tables" />
<property name="eclipselink.ddl-generation.output-mode"
value="database" />
</properties>
</persistence-unit>
<persistence-unit name="BhaveshEMFPU"
transaction-type="RESOURCE_LOCAL">
<class>edu.bhavesh.jpa.eclipselink.model.Family
</class>
<class>edu.bhavesh.jpa.eclipselink.model.Person
</class>
<class>edu.bhavesh.jpa.eclipselink.model.Job
</class>
<class>edu.bhavesh.jpa.eclipselink.model.Address
</class>
</persistence-unit>
</persistence>

Now we have our entities and persistence.xml ready. Next step is to store data into Database.

Use the File > New > Other > Java > Class wizard. Click Next >. On Java Class dialog box, put StoreData in the Class Name field, edu.bhavesh.jpa.eclipselink in the Package field and click Finish. Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;

import edu.bhavesh.jpa.eclipselink.model.Address;
import edu.bhavesh.jpa.eclipselink.model.CreditCardType;
import edu.bhavesh.jpa.eclipselink.model.Family;
import edu.bhavesh.jpa.eclipselink.model.Job;
import edu.bhavesh.jpa.eclipselink.model.Person;

/**
* @author Bhavesh.Thaker
*
*/
public class StoreData {

private static final String PERSISTENCE_UNIT_NAME = "JPAEclipseLinkDemoPU";

public StoreData() {

EntityManagerFactory objEntityManagerFactory = Persistence
.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager objEntityManager = objEntityManagerFactory
.createEntityManager();

// Begin a new local transaction so that we can persist a new entity
objEntityManager.getTransaction().begin();

Job softwareJob = getJob(10407.03, "Computer Programmer's Job");
objEntityManager.persist(softwareJob);

Job schoolJob = getJob(0, "School's Job");
objEntityManager.persist(schoolJob);

Address address = getAddress();
objEntityManager.persist(address);

Person bhaveshPerson = new Person();
bhaveshPerson.setFirstName("Bhavesh");
bhaveshPerson.setLastName("Thaker");
java.util.Calendar bhaveshDateOfBirth = java.util.Calendar
.getInstance();
bhaveshDateOfBirth.set(1980, 0, 15);
bhaveshPerson.setDateOfBirth(bhaveshDateOfBirth);
bhaveshPerson.setAge("29");
bhaveshPerson.setCreditCardType(CreditCardType.VISA);
bhaveshPerson.getJobList().add(softwareJob);
bhaveshPerson.setAddress(address);
objEntityManager.persist(bhaveshPerson);

Person sohamPerson = new Person();
sohamPerson.setFirstName("Soham");
sohamPerson.setLastName("Thaker");
java.util.Calendar sohamDateOfBirth = java.util.Calendar.getInstance();
sohamDateOfBirth.set(2006, 8, 7);
sohamPerson.setDateOfBirth(sohamDateOfBirth);
sohamPerson.setAge("3");
sohamPerson.setCreditCardType(CreditCardType.MASTER_CARD);
sohamPerson.getJobList().add(schoolJob);
sohamPerson.setAddress(address);
objEntityManager.persist(sohamPerson);

Family thakerFamily = new Family();
thakerFamily.setDescription("Family of the Thakers");
thakerFamily.getMembers().add(bhaveshPerson);
thakerFamily.getMembers().add(sohamPerson);
objEntityManager.persist(thakerFamily);

bhaveshPerson.setFamily(thakerFamily);
objEntityManager.persist(bhaveshPerson);

sohamPerson.setFamily(thakerFamily);
objEntityManager.persist(sohamPerson);

// Commit the transaction, which will cause the entity to be stored in
// the database
objEntityManager.getTransaction().commit();

objEntityManager.close();
objEntityManagerFactory.close();
}

private Job getJob(double salary, String description) {
Job newJob = new Job();
newJob.setSalary(salary);
newJob.setJobDescription(description);
return newJob;
}

private Address getAddress() {
Address newAddress = new Address();
newAddress.setStreet1("My Streat Address1");
newAddress.setStreet2("My Streat Address2");
newAddress.setCity("NOIDA");
newAddress.setState("Uttar Pradesh");
newAddress.setZipcode("201307");
newAddress.setCountry("India");
return newAddress;
}

/**
* @param args
*/
public static void main(String[] args) {
new StoreData();
}
}

Now right click on StoreData.java and run it as Java Application. Connect to Derby Database and you will see following. Your Database, Table has been created and data has been inserted into Tables.



Creating and Using Custom EntityManagerFactory

The EclipseLink class that takes care of creating database connection, configuring pooling, or re-using an exisiting datasource as a connection is the EntityManagerFactory. Configuring your EntityManagerFactory involves specificing the connection, and setting options. The call to createEntityManagerFactory takes the name of your persistence unit, it must match the name you put in your persistence.xml. Lets create custom EntityManagerFactory.

Use the File > New > Other > Java > Class wizard. Click Next >. On Java Class dialog box, put BhaveshEntityManagerFactory in the Class Name field, abstract in the modifiers field, edu.bhavesh.jpa.eclipselink.factory in the Package field and click Finish. Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink.factory;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

import org.eclipse.persistence.config.PersistenceUnitProperties;
import org.eclipse.persistence.jpa.PersistenceProvider;

/**
* @author Bhavesh.Thaker
* 
*/
public abstract class BhaveshEntityManagerFactory {

private static EntityManagerFactory objEntityManagerFactory = null;
private static java.util.Map<String, Object> pUProperties = new java.util.HashMap<String, Object>();

/**
* Creates a new BhaveshEntityManager object.
* 
* @return the entity manager
*/
public static EntityManager createEntityManager() {
if (objEntityManagerFactory == null)
init();

return objEntityManagerFactory.createEntityManager();
}

private static void init() {
pUProperties.put(PersistenceUnitProperties.TARGET_DATABASE, "Derby");
pUProperties.put(PersistenceUnitProperties.JDBC_DRIVER,
"org.apache.derby.jdbc.EmbeddedDriver");
pUProperties
.put(PersistenceUnitProperties.JDBC_URL,
"jdbc:derby:C:\\eclipse\\workspace\\MyDerbyDB;create=true;upgrade=true");
pUProperties.put(PersistenceUnitProperties.JDBC_USER, "admin");
pUProperties.put(PersistenceUnitProperties.JDBC_PASSWORD, "password");
pUProperties.put(PersistenceUnitProperties.JDBC_READ_CONNECTIONS_MIN,
"1");
pUProperties.put(PersistenceUnitProperties.JDBC_WRITE_CONNECTIONS_MIN,
"1");

pUProperties.put(PersistenceUnitProperties.BATCH_WRITING, "JDBC");
pUProperties.put(PersistenceUnitProperties.CLASSLOADER,
BhaveshEntityManagerFactory.class.getClassLoader());
/**
* You can turn off the Shared Cache EntityManager, to stop regular JPQL
* queries from hitting the shared cache, this is called putting your
* EntityManager in "Isolated Mode",
*/
pUProperties.put(PersistenceUnitProperties.CACHE_SHARED_DEFAULT,
"false");
pUProperties.put("eclipselink.logging.level", "FINE");
pUProperties.put("eclipselink.logging.timestamp", "false");
pUProperties.put("eclipselink.logging.session", "false");
pUProperties.put("eclipselink.logging.thread", "false");
pUProperties
.put("eclipselink.ddl-generation", "drop-and-create-tables");
pUProperties.put("eclipselink.ddl-generation.output-mode", "database");

objEntityManagerFactory = new PersistenceProvider()
.createEntityManagerFactory("BhaveshEMFPU", pUProperties);
}
}

Use the File > New > Other > Java > Class wizard. Click Next >. On Java Class dialog box, put StoreDataUsingCustomFactory in the Class Name field, edu.bhavesh.jpa.eclipselink in the Package field and click Finish. Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink;

import javax.persistence.EntityManager;

import edu.bhavesh.jpa.eclipselink.factory.BhaveshEntityManagerFactory;
import edu.bhavesh.jpa.eclipselink.model.Address;
import edu.bhavesh.jpa.eclipselink.model.CreditCardType;
import edu.bhavesh.jpa.eclipselink.model.Family;
import edu.bhavesh.jpa.eclipselink.model.Job;
import edu.bhavesh.jpa.eclipselink.model.Person;

public class StoreDataUsingCustomFactory {

public StoreDataUsingCustomFactory() {
/*
* Creating EntityManager object with configurations from custom factory
* rather then persistence.xml
*/
EntityManager objEntityManager = BhaveshEntityManagerFactory
.createEntityManager();

// Begin a new local transaction so that we can persist a new entity
objEntityManager.getTransaction().begin();

Job softwareJob = getJob(10407.03, "Computer Programmer's Job");
objEntityManager.persist(softwareJob);

Job schoolJob = getJob(0, "School's Job");
objEntityManager.persist(schoolJob);

Address address = getAddress();
objEntityManager.persist(address);

Person bhaveshPerson = new Person();
bhaveshPerson.setFirstName("Bhavesh");
bhaveshPerson.setLastName("Thaker");
java.util.Calendar bhaveshDateOfBirth = java.util.Calendar
.getInstance();
bhaveshDateOfBirth.set(1980, 0, 15);
bhaveshPerson.setDateOfBirth(bhaveshDateOfBirth);
bhaveshPerson.setAge("29");
bhaveshPerson.setCreditCardType(CreditCardType.VISA);
bhaveshPerson.getJobList().add(softwareJob);
bhaveshPerson.setAddress(address);
objEntityManager.persist(bhaveshPerson);

Person sohamPerson = new Person();
sohamPerson.setFirstName("Soham");
sohamPerson.setLastName("Thaker");
java.util.Calendar sohamDateOfBirth = java.util.Calendar.getInstance();
sohamDateOfBirth.set(2006, 8, 7);
sohamPerson.setDateOfBirth(sohamDateOfBirth);
sohamPerson.setAge("3");
sohamPerson.setCreditCardType(CreditCardType.MASTER_CARD);
sohamPerson.getJobList().add(schoolJob);
sohamPerson.setAddress(address);
objEntityManager.persist(sohamPerson);

Family thakerFamily = new Family();
thakerFamily.setDescription("Family of the Thakers");
thakerFamily.getMembers().add(bhaveshPerson);
thakerFamily.getMembers().add(sohamPerson);
objEntityManager.persist(thakerFamily);

bhaveshPerson.setFamily(thakerFamily);
objEntityManager.persist(bhaveshPerson);

sohamPerson.setFamily(thakerFamily);
objEntityManager.persist(sohamPerson);

// Commit the transaction, which will cause the entity to be stored in
// the database
objEntityManager.getTransaction().commit();

objEntityManager.close();

}

private Job getJob(double salary, String description) {
Job newJob = new Job();
newJob.setSalary(salary);
newJob.setJobDescription(description);
return newJob;
}

private Address getAddress() {
Address newAddress = new Address();
newAddress.setStreet1("My Factory Address1");
newAddress.setStreet2("My Factory Address2");
newAddress.setCity("Ahmedabad");
newAddress.setState("Gujarat");
newAddress.setZipcode("387130");
newAddress.setCountry("India");
return newAddress;
}

/**
* @param args
*/
public static void main(String[] args) {
new StoreDataUsingCustomFactory();
}
}

Now right click on StoreDataUsingCustomFactory.java and run it as Java Application. Connect to Derby Database to see your Database, Table has been created and data has been inserted into Tables.



Running JUnit TestCase for JPA

Use the File > New > Source Folder wizard. Give name test. Click Finish. Now right click project and go to Properties > Java Build Path > Libraries and click Add Library…. Select JUnit and press Next >. Select JUnit 4 from drop down and click Finish. Press OK.

Use the File > New > Other > Java > JUnit > JUnit Test Case wizard. Click Next >. On JUnit Test Case dialog box, put JPAEclipseLinkTest in the Name field, edu.bhavesh.jpa.eclipselink.test in the Package field, check setUp checkbox and click Finish. Replace the contents of the generated class with the following code:

package edu.bhavesh.jpa.eclipselink.test;

import static org.junit.Assert.assertTrue;

import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;
import javax.persistence.Persistence;
import javax.persistence.Query;

import org.junit.Before;
import org.junit.Test;

import edu.bhavesh.jpa.eclipselink.model.Address;
import edu.bhavesh.jpa.eclipselink.model.Family;
import edu.bhavesh.jpa.eclipselink.model.Job;
import edu.bhavesh.jpa.eclipselink.model.Person;

/**
* @author Bhavesh.Thaker
* 
*/
public class JPAEclipseLinkTest {

private static final String PERSISTENCE_UNIT_NAME = "JPAEclipseLinkDemoPU";
private EntityManagerFactory factory;

@Before
public void setUp() throws Exception {
factory = Persistence.createEntityManagerFactory(PERSISTENCE_UNIT_NAME);
EntityManager objEntityManager = factory.createEntityManager();

// Begin a new local transaction so that we can persist a new entity
objEntityManager.getTransaction().begin();

// Read the existing entries
Query q = objEntityManager.createQuery("select p from Person p");
// Persons should be empty

// Do we have entries?
boolean createNewEntries = (q.getResultList().size() == 0);

// No, so lets create new entries
if (createNewEntries) {
assertTrue(q.getResultList().size() == 0);

Family family = new Family();
family.setDescription("Family for the Thakers");
objEntityManager.persist(family);

Address address = getAddress();
objEntityManager.persist(address);

for (int i = 0; i < 50; i++) {
Job newJob = getJob(
new java.util.Random().nextDouble() * 23428,
"New Job No " + (i + 1));
objEntityManager.persist(newJob);

Person person = new Person();
person.setFirstName("Bhavesh_" + (i + 1));
person.setLastName("Thaker_" + (i + 1));
person.getJobList().add(newJob);
person.setFamily(family);
objEntityManager.persist(person);

family.getMembers().add(person);
objEntityManager.persist(family);
}
}

// Commit the transaction, which will cause the entity to
// be stored in the database
objEntityManager.getTransaction().commit();

// It is always good practice to close the EntityManager so that
// resources are conserved.
objEntityManager.close();

}

private Job getJob(double salary, String description) {
Job newJob = new Job();
newJob.setSalary(salary);
newJob.setJobDescription(description);
return newJob;
}

private Address getAddress() {
Address newAddress = new Address();
newAddress.setStreet1("My Streat Address1");
newAddress.setStreet2("My Streat Address2");
newAddress.setCity("NOIDA");
newAddress.setState("Uttar Pradesh");
newAddress.setZipcode("201307");
newAddress.setCountry("India");
return newAddress;
}

@Test
public void checkAvailablePeople() {

// Now lets check the database and see if the created entries are there
// Create a fresh, new EntityManager
EntityManager objEntityManager = factory.createEntityManager();

// Perform a simple query for all the Message entities
Query q = objEntityManager.createQuery("select p from Person p");

// We should have 40 Persons in the database
assertTrue(q.getResultList().size() == 50);

objEntityManager.close();
}

@Test
public void checkFamily() {
EntityManager objEntityManager = factory.createEntityManager();
// Go through each of the entities and print out each of their messages,
// as well as the date on which it was created
Query q = objEntityManager.createQuery("select f from Family f");

// We should have one family with 50 persons
assertTrue(q.getResultList().size() == 1);
assertTrue(((Family) q.getSingleResult()).getMembers().size() == 50);
objEntityManager.close();
}

@Test(expected = javax.persistence.NoResultException.class)
public void deletePerson() {
EntityManager objEntityManager = factory.createEntityManager();
// Begin a new local transaction so that we can persist a new entity
objEntityManager.getTransaction().begin();
Query q = objEntityManager
.createQuery("SELECT p FROM Person p WHERE p.firstName = :firstName AND p.lastName = :lastName");
q.setParameter("firstName", "Bhavesh_1");
q.setParameter("lastName", "Thaker_1");

Person user = (Person) q.getSingleResult();
objEntityManager.remove(user);
objEntityManager.getTransaction().commit();

Person person = (Person) q.getSingleResult();
objEntityManager.close();
}
}

Now right click on JPAEclipseLinkTest.java and run it as JUnit Test. See the test results.

You final project will look as under:



Summary

The Java Persistence API was developed as part of the EJB 3.0 specification. The API simplifies object persistence by enabling use of POJOs throughout your application and in your database.

In this article/tutorial, we learned the Java Persistence API and how to use it in Java SE desktop applications that require object persistence. You learned the following:

  • How to define persistable entities in your application
  • Important packages and classes of the API
  • How to use the API in a sample application
  • How to use the Java Persistence query language
  • How to get a reference implementation
  • How to configure your Eclipse integrated development environment (IDE) to use the API



Downloads

Downloads

JPAEclipseLinkDemo.zip contains the JPAEclipseLinkDemo project we created in this tutorial.



Resources



Feedback

I would like to hear from you! If you liked this tutorial, have some suggestions or even some corrections for me, please let me know. I track all user feedback in comments sections.

One Comment

  1. sameer says:

    Nice Tutorial. Very informative. Thanks for sharing !

Leave a Reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>