JPA dans un environnement Java SE
Par
Alexandre Snaps
La Java Persistence API permets maintenant à tout projet ne résidant pas
dans un environnement managé ou Application Server de bénéficier d'une
couche de persistance simple et transparente. Pour ce faire peu de
configuration et encore moins de programmation sont nécessaires. Ce petit
guide vous permettra de démarrer rapidement avec JPA dans un environnement
Java SE.
I. Dépendances
II. Modèle
A. Entité Personne
B. Entité Telephone
III. Configuration
IV. Utiliser nos entités
V. Conclusion
I. Dépendances
Pour bénéficier de toutes les facilitées de JPA dans un environnement
Java SE, il vous faudra tout d'abord obtenir les dépendances
nécessaires. Dans l'exemple qui suit, nous utiliseront Hibernate3
comme fournisseur. Pour ce faire les librairies Hibernate 3.2 ainsi
que Hibernate EntityManager et leurs dépendances, devront
être présente dans le classpath. En plus de ces "quelques" jars,
Hibernate nécessitera un pilote JDBC pour se connecter à votre base
de données. Ce guide utilisera PostgreSQL comme source de données.
Liste des JARs nécessaires
- Hibernate 3.2
- Hibernate EntityManager 3.2
- Driver JDBC
II. Modèle
A. Entité Personne
Ces jars présent il reste à définir vos entités. Une entité
persisté ne requière que quelques petites "modifications". Il
devra avoir un constructeur par défaut, une annotation @Entity
au niveau de classe et un champ annoté @Id qui représentera la
clé unique de l'entité.
Personne.java |
1 package jpa.model;
2
3 import javax.persistence.*;
4 import java.util.HashSet;
5 import java.util.Set;
6 import java.util.Date;
7
8 @ Entity
9 @ Table ( name = " personnes " )
10 public class Personne {
11
12 @ Id
13 @ GeneratedValue
14 private Long id = null ;
15
16 private String prenom;
17 private String nom;
18
19 @ OneToMany ( cascade = CascadeType.ALL )
20 private Set< Telephone> telephones = new HashSet< Telephone> ();
21
22 @ Column ( name = " creation " )
23 private Date dateDeCreation;
24
25 public Personne () {
26 }
27
28 public Personne (String firstName, String lastName) {
29 this .prenom = firstName;
30 this .nom = lastName;
31 }
32
33 public Long getId () {
34 return id;
35 }
36
37 public String getPrenom () {
38 return prenom;
39 }
40
41 public void setPrenom (String prenom) {
42 this .prenom = prenom;
43 }
44
45 public String getNom () {
46 return nom;
47 }
48
49 public void setNom (String nom) {
50 this .nom = nom;
51 }
52
53 public Set< Telephone> getTelephones () {
54 return telephones;
55 }
56
57 public void setTelephones (Set< Telephone> telephones) {
58 this .telephones = telephones;
59 }
60
61 public Date getDateDeCreation () {
62 return dateDeCreation;
63 }
64
65 @ PrePersist
66 protected void prePersist () {
67 this .dateDeCreation = new Date ();
68 }
69 }
|
La classe Personne comporte quelques annotations supplémentaires:
L'annotation @Table à la ligne 9 nous permets de spécifier le nom de la table dans laquelle les entités Personne seront persités. Par défaut, si celle-ci est absente, le nom de la table sera le nom de la classe. De la même façon, l'annotation de la ligne 22 permets de nommer la colonne dans laquelle l'attribut sera persisté. A nouveau le défaut est le nom de l'attribut.
L'annotation @GeneratedValue, nous libère d'attribué un identifiant unique à nos objets Personne avant de les persistés. Elle indique que la base de données attribuera elle-même une valeur. Dans le cas de PostgreSQL, hibernate créera une séquence.
Pour rendre l'exemple un peu plus intéressant, nous avons ajouté une relation unidirectionnel de Personne vers plusieurs numéro de téléphone, représenté par la classe Telephone. Pour qu'elle soit persistée dans votre base de donnée, cette association doit être annoté. Dans ce cas facile, l'annotation @OneToMany indique qu'une Personne possède plusieurs Telephone et que toutes opérations sur Personne dois "cascadé" sur les élements de la collection. Ainsi lorsque vous sauvegarder un objet Personne, ses numéros de téléphones seront également sauvegardés.
JPA introduit également la notion de Callbacks. Dans la classe nous avons introduit l'attribut date de création qui est en lecture seule. L'annotation @PrePersist (ligne 65) indique à l' EntityManager d'appeler la méthode prePersist avant d'insérer une nouvelle entité dans la base de données.
B. Entité Telephone
Telephone.java |
1 package jpa.model;
2
3 import javax.persistence.*;
4
5 @ Entity
6 @ Table ( name = " telephones " )
7 public class Telephone {
8
9 @ Id
10 @ GeneratedValue ( strategy = GenerationType.IDENTITY )
11 private Long id = null ;
12
13 private String numero;
14
15 public Telephone () {
16 }
17
18 public Telephone (String numero) {
19 this .numero = numero;
20 }
21
22 public Long getId () {
23 return id;
24 }
25
26 public String getNumero () {
27 return numero;
28 }
29
30 public void setNumero (String numero) {
31 this .numero = numero;
32 }
33 }
|
Cette deuxième classe référencée par Personne ne contient rien de spécial. Nous avons juste ajouté une indication quant à la stratégie pour l'attribution de l'identifiant unique. En précisant GenerationType.IDENTITY, contrairement à la valeur par défaut GenerationType.AUTO, Hibernate créera une séquence propre à l'entité Telephone. La séquence crée dans l'entité Personne sera elle partagée avec toute entre entité utilisant la stratégie par défaut. De plus Hibernate introduira une valeur par défaut à la colonne id, pour qu'elle soit populée avec la prochaine valeur de la séquence lors d'un insert.
III. Configuration
Ne reste plus maintenant qu'à persister des instances de Personne dans notre base de données. Pour ce faire, il faudra tout d'abord configurer JPA et Hibernate pour fonctionner avec nos deux classes et notre base de données. Cela est obtenu tout d'abord en configurant le fichier persistence.xml
persistence.xml |
1 <? xml version="1.0" encoding="UTF-8"? >
2 < persistence xmlns = " http://java.sun.com/xml/ns/persistence "
3 xmlns : xsi = " http://www.w3.org/2001/XMLSchema-instance "
4 xsi : schemaLocation = " http://java.sun.com/xml/ns/persistence http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd "
5 version = " 1.0 " >
6 < persistence-unit name = " exemple-jpa " transaction-type = " RESOURCE_LOCAL " >
7 < provider > org.hibernate.ejb.HibernatePersistence< / provider >
8 < properties >
9 < property name = " hibernate.dialect " value = " org.hibernate.dialect.PostgreSQLDialect " / >
10 < property name = " hibernate.connection.driver_class " value = " org.postgresql.Driver " / >
11 < property name = " hibernate.connection.username " value = " jpa " / >
12 < property name = " hibernate.connection.password " value = " " / >
13 < property name = " hibernate.connection.url " value = " jdbc:postgresql://localhost/jpa " / >
14 < property name = " hibernate.hbm2ddl.auto " value = " update " / >
15 < property name = " hibernate.cache.use_second_level_cache " value = " false " / >
16 < property name = " hibernate.cache.use_query_cache " value = " false " / >
17 < / properties >
18 < / persistence-unit >
19 < / persistence >
|
La balise persistence-unit permet de définir une unité de persistance que nous utiliseront pour obtenir un contexte de persistance dans notre classe principale. Pour pouvoir la référencé, il suffit de la nommer, dans notre cas "exemple-jpa". Comme cette unité de persistance ne vivra par dans un environnement managé, nous précisons donc qu'aucune transaction ne sera gérer pour nous.
Il nous faut ensuite préciser le fournisseur de persistance (ligne 7), dans notre cas il s'agit d'Hibernate.
Les propriétés qui suivent sont nécessaire à Hibernate pour persister nos entités. L'on n'y précise le "dialecte" sql de notre base de données, le pilote JDBC à utilisé, les droits et l'URL de connexion.
Les lignes 14 à 16 configurent Hibernate de sorte à maintenir le schéma de la base de données automatiquement pour nous et de ne pas utiliser de mémoire tampon.
IV. Utiliser nos entités
Persistance.java |
1 package jpa;
2
3 import jpa.model.Personne;
4 import jpa.model.Telephone;
5
6 import javax.persistence.EntityManagerFactory;
7 import javax.persistence.Persistence;
8 import javax.persistence.EntityManager;
9 import javax.persistence.EntityTransaction;
10
11 public class Persistance {
12
13 public static void main (String[] args) {
14 EntityManagerFactory emf = Persistence.createEntityManagerFactory (" exemple-jpa " );
15 EntityManager em = emf.createEntityManager ();
16 EntityTransaction entityTransaction = em.getTransaction ();
17 entityTransaction.begin ();
18 Personne personne = new Personne (" Alexandre " , " Snaps " );
19 em.persist (personne);
20 System.out.println (personne.getId () + " / " + personne.getDateDeCreation ());
21 personne.getTelephones ().add (new Telephone (" 123-123-1234 " ));
22 entityTransaction.commit ();
23 em.close ();
24 emf.close ();
25 }
26 }
|
La classe Persistance bootstrap JPA à la ligne 13. L'EntityManagerFactory utilise le fichier peristence.xml pour se configurer et nous permets ensuite d'obtenir un context de persistance (EntityManager). C'est à son aide que nous persistons l'objet personne à la ligne 19 dans notre base de données. Dès qu'une instance est persistée, elle également managée pour vous. Ainsi toute modification effectuée (comme en ligne 21) sera persisté dans la base données. Le tout est encapsulé dans une transaction ACID.
La sortie écran ligne 20 reprends les 2 valeurs attribuées au moment de l'insert par notre méthode callback d'abord et par JPA ensuite, en l'occurrence la date de création (callback) et l'id.
Pour ensuite recharger l'entité, il vous suffit de faire cet appel:
|
Personne personne = em.find (Personne.class , id);
|
V. Conclusion
Ceci n'est ici qu'un petit aperçût dans le monde de la persistance transparente. En effet, plusieurs modifications seraient souhaitables à notre exemple pour qu'il soit plus "parfait". Nous tâcherons de remédier à ces divers problèmes dans un futur articles. Mais ce que nous venons d'entreprendre ensemble vous permets de profiter maintenant de JPA dans un environnement Java SE.
Ce document est issu de http://www.developpez.com et reste la propriété exclusive de son auteur.
La copie, modification et/ou distribution par quelque moyen que ce soit est soumise à l'obtention préalable de l'autorisation de l'auteur.