Java Persistence API (JPA) with Eclipse

1.1. Overview

The Java persistence API (JPA) allows you to store data from POJO's (Plain old Java Objects) into database tables.

The persistence metadata is specified using Java annotations, XML mapping files or acombination of both. In case both are used then the XML information overwrites the annotations in the Java code. This persistence metadata defines the mapping to the database and the relationship between the objects.

The JPA requires that you identify the classes that you will store in a database. JPA uses the term Entity to define classes / interfaces that it will map to a relational database.

The Java compiler will use the metadata information (from the annotations or the XML file) to perform the correct database operations.

Although this should not be used in a production environment OpenJPA has also the option to create the necessary database tables automatically from the classes.

1.2. Changing the classpath

Both EclipseLink and OpenJPA requires that the JPA library are added to the classpath to use JPA.

My example will be using Derby as a database. Download Derby and add Derby.jar to your classpath.

1.3. Using EclipseLink

Download the EclipseLink implementation from http://www.eclipse.org/eclipselink/downloads/ and unpack it to a folder "ecliselink". The download contains several jars. Add the following jars to your project classpath:

  • eclipselink.jar

  • persistence.jar

1.4. Using Apache OpenJPA

Alternative to the EclipseLink JPA implementation you could also use the Apache OpenJPA implementation.

Download the Apache OpenJPA implementation from http://openjpa.apache.org and unpack it to a folder "myopenjpa". The download contains several jars. Add these jars to your project classpath.

Tip

Please note that you need the openjpa-*.jar from the folder "myopenjpa" as well as all the library out of the folder "myopenjpa/lib" folder.

2. Using the JPA with Annotations

The following describes the usage of annotations for describing the persistence metadata.

2.1. Entity

A persistable class must be annotated with javax.persistence.Entity. Entity classes will become a table in a relational database. The instances of the class will be a row in the table. The Java Persistence API implementation will create a table for the entity in your relational database. By default, the table name corresponds to the class name. You can change this with the addition to the annotation @Table(name="NEWTABLENAME")

All entities must have a primary key. Keys can be a single field or a combination of fields.

JPA allows also to auto generate the primary key in the database via the @GeneratedValue annotation.

2.2. Fields and Property setters and getters

The Java Persistence API supports that you can either uses your instance variables or your uses your Java Bean conform property getters and setters for reading and saving the elements from and to the database.

If you would to use the instance variables you annotate the variable. If you want to use the getter and setting you annotate them. You are not allowed to mix both methods.

Tip

If you annotate the instance variables then the persistence implementation will directly access them. This is for example useful if you don't want to implement a setter method.

All properties or fields that should not be persisted must be explicitly marked with @Transient.

By default the entity field or property name is used for the column name in the table. You can change the default name via @Column(name="newColumnName").

The following annotations can be used for fields and / or getter and setters.

Table 1. Annotations for fields / getter and setter

@Id Identifies the uniqui ID of the database entry
@GeneratedValue Together with ID defines that this value is generated automatically.
@Transient Field will not be saved in database

2.3. Relationships

Relationships between classes can be expressed. Classes can have one to one, one to many, many to one, and many to many relationships with other classes.

A relationship can be bidirectional or unidirectional, e.g. in a bidirectional relationship both classes store a reference to each other while in an unidirectional case only one class has a reference to the other class.

Table 2. Relationship annotations

OneToOne
OneToMany
ManyToOne
ManyToMany

2.4. Example

The following shows our example class with the annotations for the persistence metadata. The ID will be automatically be created by the database. The field nonsenseField will not be persisted to the database.

  
package datamodel;

import java.util.List;

import javax.persistence.ManyToOne;

import datamodel.impl.Family;
import datamodel.impl.Job;


public interface IPerson {

public abstract String getId();

public abstract void setId(String Id);

public abstract String getFirstName();

public abstract void setFirstName(String firstName);

public abstract String getLastName();

public abstract void setLastName(String lastName);

public Family getFamily();

public void setFamily(Family family);

public abstract List getJobList();

public abstract void setJobList(List jobs);

public abstract String getNonsenseField();

public abstract void setNonsenseField(String nonsenseField);

}

  
package datamodel.impl;

import java.util.ArrayList;
import java.util.List;

import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import javax.persistence.ManyToOne;
import javax.persistence.OneToMany;
import javax.persistence.OrderBy;
import javax.persistence.Transient;


import datamodel.IPerson;

@Entity
public class Person implements IPerson {


private String id;
private String firstName;
private String lastName;

private Family family;

private String nonsenseField = "";


private List jobList = new ArrayList();

@Id
@GeneratedValue(strategy=GenerationType.SEQUENCE)
public String getId() {
return id;
}

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


public String getFirstName() {
return firstName;
}

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

// Leave the standard column name of the table
public String getLastName() {
return lastName;
}

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


@ManyToOne
public Family getFamily() {
return family;
}

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

@Transient
public String getNonsenseField() {
return nonsenseField;
}

public void setNonsenseField(String nonsenseField) {
this.nonsenseField = nonsenseField;
}

@OneToMany
public List getJobList() {
return this.jobList;
}

public void setJobList(List nickName) {
this.jobList = nickName;
}


}

  
package datamodel;

public interface IJob {

public abstract String getId();

public abstract void setId(String id);

public abstract double getSalery();

public abstract void setSalery(double salery);

public abstract String getJobDescr();

public abstract void setJobDescr(String jobDescr);

}

  
package datamodel.impl;

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

import datamodel.IJob;


@Entity
public class Job implements IJob {
@Id
@GeneratedValue(strategy = GenerationType.SEQUENCE)
private String id;
private double salery;
private String jobDescr;

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

public double getSalery() {
return salery;
}

public void setSalery(double salery) {
this.salery = salery;
}

public String getJobDescr() {
return jobDescr;
}

public void setJobDescr(String jobDescr) {
this.jobDescr = jobDescr;
}

}

3. Using the JPA with XML metadata

3.1. XML Metadata

Alternative to the annotations you can also use XML metadata to define the persistence metadata.

You can create a file orm.xml within the META-INF directory to describes this data.

3.2. Example

The following file describes the persistence data in an external file orm.xml. No annotations are required in Person.java. We use for illustration a simplified example of person.

  
package datamodel;


public interface IPerson {

public abstract String getId();

public abstract void setId(String Id);

public abstract String getFirstName();

public abstract void setFirstName(String firstName);

public abstract String getLastName();

public abstract void setLastName(String lastName);

public abstract String getNonsenseField();

public abstract void setNonsenseField(String nonsenseField);

}

  
package datamodel;

import javax.persistence.*;

@Entity
@Table(name="MYAPPLICATION.PEOPLETABLE")

public class Person implements IPerson {
private String id;
private String firstName;
private String lastName;
private String nonsenseField="";

@Id
public String getId() {
return id;
}

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

// Name the column to "MYFIRST"
@Column(name="MYFIRST")
public String getFirstName() {
return firstName;
}
public void setFirstName(String firstName) {
this.firstName = firstName;
}

// Leave the standard column name of the table
public String getLastName() {
return lastName;
}
public void setLastName(String lastName) {
this.lastName = lastName;
}

@Transient
public String getNonsenseField() {
return nonsenseField;
}

public void setNonsenseField(String nonsenseField) {
this.nonsenseField = nonsenseField;
}
}

This is required orm.xml for this mapping.

  







4. Persistence Units

4.1. Overview

     A set of entities which are logical connected will be grouped via a persistence unit.
These persistence units are described via a file persistence.xml
in the directory META-INF in the source folder.This directory must be part of the build path otherwise it
will not be found.
In this file the database driver, the database location, the user and the password is specified.
Each JPA provider is free to define its own parameter valuesfor the database connection,
user, password, etc.   

4.2. EcliseLink

The following is the persistence file for EclipseLink.

Please adjust the path of your database which will be created to your liking.



org.eclipse.persistence.jpa.PersistenceProvider



datamodel.impl.Family

datamodel.impl.Person

datamodel.impl.Job


4.3. Apache OpenJPA

The following is the persistence file for OpenJPA.

Please adjust the path of your database which will be created to your liking.

  
org.apache.openjpa.persistence.PersistenceProviderImpl

5. Entity Manager

5.1. Overview

The class Entity Manager is used to persists the Java Classes.

Implement the the following coding.

This code will create the database tables if started the first time and create a few test entries.

After the test entries are created,

they will be read and the one field of the entries is changed and saved to the database.

  
package main;

import java.util.List;

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

import datamodel.IFamily;
import datamodel.IJob;
import datamodel.IPerson;
import datamodel.impl.Family;
import datamodel.impl.Job;
import datamodel.impl.Person;

public class Main {
public static void main(String[] args) {
// Create the Entity Manager
EntityManagerFactory factory = Persistence
.createEntityManagerFactory("people");
EntityManager em = factory.createEntityManager();

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

// Read the existing entries
Query q = em.createQuery("select m from Person m");
// Do we have entries?
boolean createNewEntries = (q.getResultList().size() == 0);
// No, so lets create new entries
if (createNewEntries) {
Family family = new Family();
family.setDescription("MyFamily");


for (int i = 0; i < newperson =" new"
job =" new" em2 =" factory.createEntityManager();
" q =" em2.createQuery(">) q.getResultList()) {
System.out.println("Say hello to " + m.getFirstName() + " "
+ m.getLastName());
// Job will always be filled in this example
IJob job = m.getJobList().get(0);
System.out.println("He earns " + job.getSalery()
+ " in his job as " + job.getJobDescr());
// Lets printout the family he belongs to
System.out.println("Family " +m.getFamily().getDescription());
// Same here, nickname will in this example always be filled.
}

}
}

6. Reverse Mapping with OpenJPA

6.1. Overview

OpenJPA includes a tools for creating persistence metadata from an existing data, e.g. databases and annotated classes.

The following show an example on how to create a valid orm.xml file from an annotated class.

Put the following ant script in your folder src of the example with an annotated java file and run it.

It will create under the folder build a valid orm.xml from your annotations.

   

7. Links and Literature

7.1. Java Persistence API Resources

http://openjpa.apache.org T

he Apache OpenJPA implementation

http://openjpa.apache.org/documentation.html

The Apache OpenJPA implementation documentation

http://java.sun.com/developer/technicalArticles/J2SE/Desktop/persistenceapi/

Using the Java Persistence API in Desktop Applications

0 comments: