Dans la série “Vivre sans Spring / Hibernate”, découvrons Apache Torque, un framework ORM qui comble quelques lacunes de son concurrent.
Introduction
Dans le cadre de mon projet “full Apache” (enfin presque, le front-end et la base de données n’utilisent pas de composants Apache), il faut pouvoir accéder aux données et les transformer en objets.
Choix habituel
Comme expliqué dans l’article relatif à la suppression de Spring, la couche ORM (Object-Relational mapping) est la plupart du temps confiée à Hibernate. C’est un framework qui fonctionne globalement bien mais qui impose rapidement l’usage de queries SQL (au travers de JPQL), réduisant ainsi la maintenabilité de l’application.
Apache Torque, un autre ORM
Tout comme Hibernate, Apache Torque remplit la fonction ORM en permettant la création, la modification, la suppression et la recherche d’enregistrements. Il permet également la création des tables et des entités à partir d’un schéma XML (je demande à voir comment modifier une table avec des enregistrements en production). Et là où Torque est meilleur que son concurrent Hibernate, c’est dans la programmation des recherches.
Exemple de recherche avec Torque
Exemple de recherche avec Hibernate
On voit immédiatement que Apache Torque propose une maintenabilité bien meilleure: on peut facilement renommer la propriété “ISBN” dans l’entité et les recherches associées. Tandis qu’avec Hibernate, il va falloir repasser sur toutes les requêtes JPQL (autant dire que c’est lourd).
Configuration
La configuration est relativement simple puisqu’elle consiste à compléter le fichier pom.xml.
Étape 1: ajouter le plugin Torque
Le plugin Maven “torque-maven-plugin” est responsable de créer le fichier SQL représentant les tables de la base et également de créer les entités. En gras, il s’agit des propriétés modifiables selon son projet et environnement.
1<plugin>
2 <groupId>org.apache.torque</groupId>
3 <artifactId>torque-maven-plugin</artifactId>
4 <version>4.0</version>
5 <executions>
6 <execution>
7 <id>generate-sources</id>
8 <phase>generate-sources</phase>
9 <goals>
10 <goal>generate</goal>
11 </goals>
12 <configuration>
13 <packaging>classpath</packaging>
14 <configPackage>org.apache.torque.templates.om</configPackage>
15 <sourceDir>src/main/schema</sourceDir>
16 <options> <torque.om.package>ch.gobothegeek.entites</torque.om.package>
17 <torque.database>mysql</torque.database>
18 </options>
19 </configuration>
20 </execution>
21 <execution>
22 <id>generate-sql</id>
23 <phase>generate-sources</phase>
24 <goals>
25 <goal>generate</goal>
26 </goals>
27 <configuration>
28 <packaging>classpath</packaging>
29 <configPackage>org.apache.torque.templates.sql</configPackage>
30 <sourceDir>src/main/schema</sourceDir>
31 <defaultOutputDir>target/generated-sql</defaultOutputDir>
32 <defaultOutputDirUsage>none</defaultOutputDirUsage>
33 <options>
34 <torque.database>mysql</torque.database>
35 </options>
36 </configuration>
37 </execution>
38 </executions>
39 <dependencies>
40 <dependency>
41 <groupId>org.apache.torque</groupId>
42 <artifactId>torque-templates</artifactId>
43 <version>4.0</version>
44 </dependency>
45 </dependencies>
46 </plugin>
Étape 2: ajouter le plugin SQL
Ce plugin Maven va, pour sa part, assurer l’exécution des requêtes SQL générées par Apache Torque. En gras, comme précédemment, il s’agit des informations à modifier selon son projet et environnement.
1 <plugin>
2 <groupId>org.codehaus.mojo</groupId>
3 <artifactId>sql-maven-plugin</artifactId>
4 <version>1.4</version>
5 <configuration>
6 <driver>org.gjt.mm.mysql.Driver</driver>
7 <url>jdbc:mysql://localhost:3306/base</url>
8 <username>torque</username>
9 <password>********</password>
10 <onError>continue</onError>
11 <autocommit>true</autocommit>
12 <fileset>
13 <basedir>${basedir}/target/generated-sql</basedir>
14 <includes>
15 <include>*.sql</include>
16 </includes>
17 </fileset>
18 </configuration>
19 <dependencies>
20 <dependency>
21 <groupId>org.mariadb.jdbc</groupId>
22 <artifactId>mariadb-java-client</artifactId>
23 <version>2.7.3</version>
24 </dependency>
25 </dependencies>
26 </plugin>
Étape 3: configurer Torque
Il faut maintenant ajouter plusieurs éléments pour que Torque puisse générer les entités. D’abord il faut définir l’arborescence nécessaire: dans le dossier src/main, on ajoute le dossier torque-gen/ puis dans torque-gen/ on ajoute les dossiers conf/, outlets/, resources/ et templates.
Dans le dossier torque-gen/conf/, on ajoute le fichier control.xml suivant:
1<?xml version="1.0" encoding="UTF-8"?>
2<control loglevel="debug"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://db.apache.org/torque/4.0/generator/configuration http://db.apache.org/torque/4.0/generator/configuration.xsd"
5 xmlns="http://db.apache.org/torque/4.0/generator/configuration">
6
7 <output name="torque.om.dbObject" existingTargetStrategy="skip" outputDirKey="modifiable">
8 <filenameOutlet
9 xsi:type="javaOutlet"
10 class="org.apache.torque.generator.outlet.java.JavaFilenameOutlet">
11 <mergepoint name="package">
12 <action
13 xsi:type="sourceElementAttributeAction"
14 element="."
15 attribute="dbObjectPackage"
16 acceptNotSet="false"/>
17 </mergepoint>
18 <mergepoint name="classname">
19 <action
20 xsi:type="sourceElementAttributeAction"
21 element="."
22 attribute="dbObjectClassName"
23 acceptNotSet="false"/>
24 </mergepoint>
25 </filenameOutlet>
26 <source xsi:type="fileSource"
27 elements="database/table">
28 <transformer class="org.apache.torque.templates.transformer.om.OMTransformer"/>
29 <include>*schema.xml</include>
30 <exclude>id-table-schema.xml</exclude>
31 </source>
32 <outlet name="torque.om.dbObject"/>
33 </output>
34</control>
Utilisation
Étape 1: préparer le fichier XML de schéma
Ici, il faut ajouter le dossier src/main/schema (configurable via la propriété “sourceDir” du plugin Torque) puis y créer un fichier xml dont le nom doit obligatoirement se terminer par schema.xml. Le contenu de ce fichier (nommé book-schema.xml pour cet exemple) doit ressembler à ceci:
1<?xml version="1.0" encoding="ISO-8859-1" ?>
2<database xmlns="http://db.apache.org/torque/5.0/templates/database"
3 xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
4 xsi:schemaLocation="http://db.apache.org/torque/5.0/templates/database
5 http://db.apache.org/torque/torque-5.0/documentation/orm-reference/database-5-0-strict.xsd"
6 name="bookstore"
7 defaultIdMethod="native">
8
9 <table name="book" description="Book Table">
10 <column
11 name="book_id"
12 required="true"
13 primaryKey="true"
14 type="INTEGER"
15 description="Book Id"/>
16 <column
17 name="title"
18 required="true"
19 type="VARCHAR"
20 size="255"
21 description="Book Title"/>
22 <column
23 name="isbn"
24 required="true"
25 type="VARCHAR"
26 size="24"
27 javaName="ISBN"
28 description="ISBN Number"/>
29 <column
30 name="publisher_id"
31 required="true"
32 type="INTEGER"
33 description="Foreign Key Publisher"/>
34 <column
35 name="author_id"
36 required="true"
37 type="INTEGER"
38 description="Foreign Key Author"/>
39 </table>
40</database>
Étape 2: transformer le fichier de schéma entités
Rien de complexe ici, il faut d’abord invoquer Maven avec “mvn generate-sources” afin qu’il prépare les entités et les requêtes.
A l’issue de l’exécution, si tout s’est déroulé correctement, vous obtenez les fichiers suivants:
- target/generated-sources/ch/gobothegeek/entites/Book.java
- target/generated-sources/ch/gobothegeek/entites/BookPeer.java
- target/generated-sources/ch/gobothegeek/entites/BookPeerImpl.java
- target/generated-sources/ch/gobothegeek/entites/BookRecordMapper.java
- target/generated-sql/book-schema.sql
Le fichier SQL obtenu se présente comme ceci:
1-- -----------------------------------------------------------------------
2-- mysql SQL script for schema bookstore
3-- -----------------------------------------------------------------------
4
5
6drop table if exists book;
7
8
9
10# -----------------------------------------------------------------------
11# book
12# -----------------------------------------------------------------------
13CREATE TABLE book
14(
15 book_id INTEGER NOT NULL AUTO_INCREMENT,
16 title VARCHAR(255) NOT NULL,
17 isbn VARCHAR(24) NOT NULL,
18 publisher_id INTEGER NOT NULL,
19 author_id INTEGER NOT NULL,
20 PRIMARY KEY(book_id)
21);
Étape 3: exécuter le fichier SQL
Il faut maintenant invoquer Maven avec “mvn sql:execute” afin que les requêtes soient exécutées en base de données, en utilisant le fichier SQL généré lors de l’étape précédente. A la fin du processus, on peut se connecter sur la base (ici j’ai utilisé dBeaver) et constater que la table est bien créée:
Modifier une table existante
Si la création des tables est globalement facile, dans la vraie vie on est souvent amené à modifier des tables existantes qui contiennent des données. La documentation Apache étant plutôt légère sur ce point, je vais tester une modification simple: ajouter une colonne.
Pour cela, j’ai ajouté un enregistrement en base puis je modifie le fichier XML book-schema.xml et j’ajoute ceci:
Je relance le processus avec “mvn generate-sources”. On obtient alors le fichier de requêtes suivant:
1-- -----------------------------------------------------------------------
2-- mysql SQL script for schema bookstore
3-- -----------------------------------------------------------------------
4
5
6drop table if exists book;
7
8
9
10# -----------------------------------------------------------------------
11# book
12# -----------------------------------------------------------------------
13CREATE TABLE book
14(
15 book_id INTEGER NOT NULL AUTO_INCREMENT,
16 title VARCHAR(255) NOT NULL,
17 isbn VARCHAR(24) NOT NULL,
18 publisher_id INTEGER NOT NULL,
19 author_id INTEGER NOT NULL,
20 stock INTEGER NOT NULL,
21 PRIMARY KEY(book_id)
22);
Inutile d’exécuter en base puisque la table sera supprimée et les données perdues.
Conclusion
On a vu ici comment configurer et utiliser Apache Torque en remplacement d’Hibernate. Dans le prochain article sur Torque, on verra comment améliorer la configuration et permettre de générer des requêtes SQL de modification des tables.