Thursday, October 16, 2014

Java Persistence API with EclipseLink

(I created a new version of this exercise with Hibernate and Maven here)

In this message, I will provide a fully working example on Java Persistence API (JPA) using EclipseLink in a stand-alone program. I.e., this example can (and should) run outside any Application Server. Again, I am assuming that you are using Eclipse for Java EE developers.

The first thing you must do is to create a JPA project (change to Java EE or JPA view on the upper right corner of the Eclipse Window):




Let us call Players to our project, as we will store information of football teams on the database.


If you press "Next" a couple of times you'll end up having to chose the specific JPA implementation. EclipseLink might not be available on the first time. If that happens, you must install it, using the floppy disk image on the right:


We may now create the classes. In fact, we are going to create specially annotated classes that are Entities:


Let us call "Player" to the first one:

And now, it is time to program the Player Entity class. I will not take long explaining the details, as, with some effort, you may find explanations for all the annotations on the web. I will just say that many players can belong to the same Team, and therefore, we use the @ManyToOne annotation:
package data;

import java.io.Serializable;
import java.util.Date;

import javax.persistence.*;

/**
 * Entity implementation class for Entity: Player
 *
 */
@Entity
public class Player implements Serializable {
private static final long serialVersionUID = 1L;
@Id @GeneratedValue(strategy=GenerationType.AUTO)
private int id;
private String name;
@Temporal(TemporalType.DATE)
private Date birth;
private float height;
@ManyToOne
private Team team;
public Player() {
super();
}

public Player(String name, Date birth, float height, Team team) {
super();
this.name = name;
this.birth = birth;
this.height = height;
this.team = team;
}

public String getName() {
return name;
}

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

public Date getBirth() {
return birth;
}

public void setBirth(Date birth) {
this.birth = birth;
}

public float getHeight() {
return height;
}

public void setHeight(float height) {
this.height = height;
}

public Team getTeam() {
return team;
}

public void setTeam(Team team) {
this.team = team;
}

public static long getSerialversionuid() {
return serialVersionUID;
}
@Override
public String toString() {
return this.name + " id = " + this.id + ", " + this.height + " plays for " + this.team.getName() + ". Born on " + this.birth;
}
   
}

Let us now go for the Team Entity class, which has the converse annotation @OneToMany. This defines a bi-directional relation, which is to say, we may access the Team from the Player object, whereas accessing the Player from the Team object is also possible. The mappedBy indication serves to indicate that the Entity Player is the owner of the relation. In practice, the database table storing Player data will have an additional column to keep the identifier (foreign key) of the Team the player belongs to.



package data;

import java.io.Serializable;
import java.util.List;

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

@Entity
public class Team implements Serializable {
private static final long serialVersionUID = 1L;
@Id @GeneratedValue(strategy=GenerationType.AUTO)
int id;
private String name;
private String address;
private String presidentname;
@OneToMany(mappedBy="team")
private List<Player> players;
public Team() {
super();
}
public Team(String name, String address, String presidentname) {
super();
this.name = name;
this.address = address;
this.presidentname = presidentname;
}

public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public String getPresidentname() {
return presidentname;
}
public void setPresidentname(String presidentname) {
this.presidentname = presidentname;
}
public List<Player> getPlayers() {
return players;
}
public void setPlayers(List<Player> players) {
this.players = players;
}

}



A few fundamental steps are missing. First, we need to create the database. I'm using MySQL. In my case, creating the database and granting permissions goes like this:


One of the most daunting tasks with JPA is to get the persistence.xml file right. This one works for me. Take care of using the right username and password. Maybe even the database, if it is not MySQL:
<?xml version="1.0" encoding="UTF-8"?>
<persistence version="2.1"
xmlns="http://xmlns.jcp.org/xml/ns/persistence" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://xmlns.jcp.org/xml/ns/persistence http://xmlns.jcp.org/xml/ns/persistence/persistence_2_1.xsd">
<persistence-unit name="Players">
<class>data.Player</class>
<class>data.Team</class>
<properties>
<property name="javax.persistence.jdbc.user" value="artur" />
<property name="javax.persistence.jdbc.password" value="****" />
<property name="javax.persistence.jdbc.url" value="jdbc:mysql://localhost:3306/PlayersAndTeams" />
<property name="javax.persistence.jdbc.driver" value="com.mysql.jdbc.Driver" />

<property name="eclipselink.ddl-generation" value="create-tables" />
<property name="eclipselink.ddl-generation.output-mode"
value="database" />
</properties>

</persistence-unit>
</persistence>


Since we reference a JDBC driver, we need to include one, in a few steps:


Pick "Add External JARs..." and add a MySQL or other appropriate driver. You need to store it on your disk, maybe inside the Eclipse project:



Let us now write a program that stores actual data to the database. One should notice that the Team is inserted on the Player side, as the Player owns the relation (from my experience with my concrete choices of technologies, any attempt to do the opposite, entering the Player on the Team side, will result in losing all data):
package data;

import java.util.Calendar;
import java.util.Date;

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

public class WriteData {

public static Date getDate(int day, int month, int year) {
Calendar cal = Calendar.getInstance();
cal.set(Calendar.YEAR, year);
cal.set(Calendar.MONTH, month - 1);
cal.set(Calendar.DAY_OF_MONTH, day);

Date d = cal.getTime();
return d;
}

public static void main(String[] args) {
Team [] teams = { new Team("Sporting", "Alvalade", "Carvalho"), new Team("Academica", "Coimbra", "Simões"), new Team("Porto", "Antas", "Costa"), new Team("Benfica", "Luz", "Vieira") };
Player [] players = { 
new Player("Albino", getDate(23,4,1987), 1.87f, teams[0]), 
new Player("Bernardo", getDate(11,4,1987), 1.81f, teams[0]), 
new Player("Cesar", getDate(12,5,1983), 1.74f, teams[0]), 
new Player("Dionisio", getDate(3,12,1992), 1.67f, teams[0]), 
new Player("Eduardo", getDate(31,8,1985), 1.89f, teams[0]), 
new Player("Franco", getDate(6,1,1989), 1.95f, teams[1]), 
new Player("Gil", getDate(7,12,1986), 1.8f, teams[1]), 
new Player("Helder", getDate(14,5,1987), 1.81f, teams[1]), 
new Player("Ilidio", getDate(13,6,1991), 1.82f, teams[1]), 
new Player("Jacare", getDate(4,2,1993), 1.83f, teams[1]), 
new Player("Leandro", getDate(4,10,1984), 1.81f, teams[2]), 
new Player("Mauricio", getDate(3,6,1984), 1.8f, teams[2]), 
new Player("Nilton", getDate(11,3,1985), 1.88f, teams[2]), 
new Player("Oseias", getDate(23,11,1990), 1.74f, teams[2]), 
new Player("Paulino", getDate(14,9,1986), 1.75f, teams[2]), 
new Player("Quevedo", getDate(10,10,1987), 1.77f, teams[2]), 
new Player("Renato", getDate(7,7,1991), 1.71f, teams[3]), 
new Player("Saul", getDate(13,7,1992), 1.86f, teams[3]), 
new Player("Telmo", getDate(4,1,1981), 1.88f, teams[3]), 
new Player("Ulisses", getDate(29,8,1988), 1.84f, teams[3]), 
new Player("Vasco", getDate(16,5,1988), 1.83f, teams[3]), 
new Player("X", getDate(8,12,1990), 1.82f, teams[3]), 
new Player("Ze", getDate(13,5,1987), 1.93f, teams[3]), 
};
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Players");
EntityManager em = emf.createEntityManager();
EntityTransaction trx = em.getTransaction();
trx.begin();
for (Team t : teams)
em.persist(t);
for (Player p : players)
em.persist(p);
trx.commit();
}

}


This program is very quiet. No output, or only a couple of log messages is a good sign.

Since we stored the data, we may now run a query to retrieve it. Notice that we are getting a team from the name, and then we print all the players of the team, despite never having inserted the data this way (we inserted it in the opposite direction):
package data;

import java.util.List;

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

public class ReadData {

public static void main(String[] args) {
EntityManagerFactory emf = Persistence.createEntityManagerFactory("Players");
EntityManager em = emf.createEntityManager();
Query q = em.createQuery("from Team t where t.name = :t");
q.setParameter("t", "Academica");
@SuppressWarnings("unchecked")
List<Team> resultteams = q.getResultList();
if (resultteams.size() > 0)
for (Player p : resultteams.get(0).getPlayers())
System.out.println(p);
}

}


The registered players of this outstanding team are:

Jacare id = 14, 1.83 plays for Academica. Born on Thu Feb 04 00:00:00 WET 1993
Ilidio id = 13, 1.82 plays for Academica. Born on Thu Jun 13 00:00:00 WEST 1991
Gil id = 11, 1.8 plays for Academica. Born on Sun Dec 07 00:00:00 WET 1986
Franco id = 10, 1.95 plays for Academica. Born on Fri Jan 06 00:00:00 WET 1989
Helder id = 12, 1.81 plays for Academica. Born on Thu May 14 00:00:00 WEST 1987

That's exactly what we inserted. If you got this result everything went well.

Finally, it is worthwhile to see how do the tables look like:



No comments:

Post a Comment