Quarkus JPA PostgreSQL
Quarkus JPA PostgreSQL
• une API Rest partielle (GET) avec JAX-RS et Quarkus sur une source de données
JPA ;
• des tests unitaires ;
• des tests d'intégration au niveau API (http) avec un PostGreSQL lancé par un plugin
maven Docker ;
• une distribution native, compilée avec GraalVM et une image docker de l'application
compilée.
Pour réagir au contenu de cet article, un espace de dialogue vous est proposé sur le forum
Commentez.
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
I - Choix techniques.....................................................................................................................................................3
II - Qu'est-ce que Quarkus.......................................................................................................................................... 3
III - Structure globale du projet................................................................................................................................... 3
IV - Maven et son pom.xml......................................................................................................................................... 5
V - Les plugins de build.............................................................................................................................................. 7
VI - Un simple /ping................................................................................................................................................... 10
VII - Compilation en binaire avec GraalVM...............................................................................................................13
VII-A - Installation de SDKMAN........................................................................................................................... 13
VII-B - Installation de GraalVM............................................................................................................................ 13
VII-C - Compilation en code natif........................................................................................................................ 14
VIII - Configuration de l'accès aux données............................................................................................................. 15
VIII-A - Lancement de PostgreSQL via Docker...................................................................................................15
VIII-B - Paramétrage de l'application................................................................................................................... 16
IX - Des entités à rendre persistantes...................................................................................................................... 17
IX-A - VideoGame et Genre.................................................................................................................................17
IX-B - Producers CDI et annotation..................................................................................................................... 18
IX-C - Le repository CRUD avec Spring Data JPA............................................................................................. 19
X - Le endpoint REST JAX-RS................................................................................................................................. 19
XI - Convertisseur générique pour les valeurs de l'enum......................................................................................... 21
XII - Tests...................................................................................................................................................................26
XII-A - Tests unitaires...........................................................................................................................................26
XII-B - Tests d'intégration..................................................................................................................................... 26
XIII - Version native et image Docker....................................................................................................................... 30
XIV - Health Check et Metrics...................................................................................................................................32
XV - Conclusions....................................................................................................................................................... 34
XVI - Remerciements.................................................................................................................................................34
-2-
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
I - Choix techniques
L'objectif de cet article est de faire tourner une API REST avec Quarkus fonctionnant avec :
Nativement, Quarkus est fourni avec Google Guava, ce qui servira dans le cadre de ce tutoriel.
Quarkus : Supersonic Subatomic Java A Kubernetes Native Java stack tailored for OpenJDK HotSpot and GraalVM,
crafted from the best of breed Java libraries and standards.
En substance, c'est un framework constitué des meilleurs standards et bibliothèques Java pour réaliser des
applications pour le cloud en mode REST.
• Micronaut ;
• Thorntail ;
• SpringBoot (et toute la plateforme Spring) ;
• dans une moindre mesure, Payara-micro.
Avant de commencer à entrer dans le détail des divers éléments, voici la structure du projet Maven :
[quarkus-tuto]
├── src
│ ├── main
│ │ ├── docker
│ │ │ ├── Dockerfile.jvm
│ │ │ └── Dockerfile.native
│ │ ├── java
│ │ │ └── fr
│ │ │ └── fxjavadevblog
│ │ │ └── qjg
│ │ │ ├── genre
│ │ │ │ ├── Genre.java
│ │ │ │ ├── GenreConverterProvider.java
│ │ │ │ └── GenreResource.java
-3-
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
│ │ │ ├── health
│ │ │ │ └── SimpleHealthCheck.java
│ │ │ ├── ping
│ │ │ │ └── PingService.java
│ │ │ ├── utils
│ │ │ │ ├── GenericEnumConverter.java
│ │ │ │ ├── InjectUUID.java
│ │ │ │ └── UUIDProducer.java
│ │ │ ├── videogame
│ │ │ │ ├── VideoGame.java
│ │ │ │ ├── VideoGameFactory.java
│ │ │ │ ├── VideoGameRepository.java
│ │ │ │ └── VideoGameResource.java
│ │ │ └── ApiDefinition.java
│ │ └── resources
│ │ ├── application.properties
│ │ └── import.sql
│ ├── test
│ │ ├── java
│ │ │ └── fr
│ │ │ └── fxjavadevblog
│ │ │ └── qjg
│ │ │ ├── global
│ │ │ │ └── TestingGroups.java
│ │ │ ├── ping
│ │ │ │ └── PingTest.java
│ │ │ └── utils
│ │ │ ├── CDITest.java
│ │ │ ├── DummyTest.java
│ │ │ └── GenericEnumConverterTest.java
│ │ └── resources
│ │ └── application.properties
│ └── test-integration
│ ├── java
│ │ └── fr
│ │ └── fxjavadevblog
│ │ └── qjg
│ │ ├── utils
│ │ │ └── IT_DummyTest.java
│ │ └── videogame
│ │ └── IT_VideoGameResource.java
│ └── resources
│ └── application.properties
├── target
│ ├── classes
│ │ ├── application.properties
│ │ └── import.sql
│ └── test-classes
│ └── application.properties
├── .dockerignore
├── README.md
└── pom.xml
• src/main : contient les sources Java main/java et les ressources pour Quarkus main\resources :
application.properties et import.sql ;
• src/test : contient les tests unitaires test/java et les ressources pour les tests unitaires sans base de données
PostgreSQL test\resources ;
• src/test-integration : contient les tests d'intégration test-integration/java et les ressources pour les tests
d’intégration avec PostgreSQL test-integration\resources ;
• src/main/docker : contient les Dockerfile nécessaires à la génération de l'image conteneurisée de
l'application.
fxjavadevblog
└── qjg
-4-
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
├── genre
│ ├── Genre.java : enum qui contient tous les genres de jeux vidéo
│ ├── GenreConverterProvider.java : fournisseur de conversion de Genre pour les
paramètres JAX-RS
│ └── GenreResource.java : point d’accès REST via JAX-RS aux genres de jeux
vidéo
├── health
│ └── SimpleHealthCheck.java : retour simple de Health Check (optionnel)
├── ping
│ └── PingService.java : pour vérifier que JAX-RS est bien opérationnel
├── utils
│ ├── GenericEnumConverter.java : convertisseur générique d’enum en Json
│ ├── InjectUUID.java : annotation pour injecter des UUID sous forme de
String
│ └── UUIDProducer.java : générateur de UUID
├── videogame
│ ├── VideoGame.java : classe métier, persistante via JPA (Hibernate)
│ ├── VideoGameFactory.java : Factory de jeux video via CDI pour bénéficier de
@InjectUUID en mode programmatique
│ ├── VideoGameRepository.java : un repository CRUD JPA généré par Spring Data JPA
│ └── VideoGameResource.java : le point d’accès REST via JAX-RS aux jeux vidéo
└── ApiDefinition.java : pour les informations de l’API via Swagger
test
├── java
│ └── fr
│ └── fxjavadevblog
│ └── qjg
│ ├── global
│ │ └── TestingGroups.java : définitions de constantes pour les groupes de
tests JUnit 5
│ ├── ping
│ │ └── PingTest.java : Vérifie que le “ping” fonctionne
│ └── utils
│ ├── CDITest.java : permet de vérifier que CDI est
opérationnel
│ ├── DummyTest.java : un test vide
│ └── GenericEnumConverterTest.java : vérification de la conversion générique
d’enum
└── resources
└── application.properties : fichier de paramétrage de Quarkus spécifique pour
les tests unitaires
DummyTest.java : un test vide afin de vérifier que les tests unitaires s'exécutent correctement
(un métatest, lol)
1. <project xmlns="http://maven.apache.org/POM/4.0.0"
2. xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
3. xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/
maven-4.0.0.xsd">
4. <modelVersion>4.0.0</modelVersion>
5. <groupId>fr.fxjavadevblog</groupId>
6. <artifactId>quarkus-tuto</artifactId>
7. <version>0.0.1-SNAPSHOT</version>
8. <name>Quarkus-JPA-PostgreSQL</name>
9. <properties>
10. <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
11. <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
12. <maven.compiler.target>1.8</maven.compiler.target>
-5-
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
13. <maven.compiler.source>1.8</maven.compiler.source>
14. <lombok.version>1.18.12</lombok.version>
15. <quarkus-version>1.3.1.Final</quarkus-version>
16. <surefire-plugin.version>2.22.2</surefire-plugin.version>
17. </properties>
18. </project>
1. <dependencies>
2. <dependency>
3. <groupId>org.projectlombok</groupId>
4. <artifactId>lombok</artifactId>
5. <version>${lombok.version}</version>
6. <scope>provided</scope>
7. </dependency>
8. </dependencies>
1. <dependencyManagement>
2. <dependencies>
3. <dependency>
4. <groupId>io.quarkus</groupId>
5. <artifactId>quarkus-bom</artifactId>
6. <version>${quarkus-version}</version>
7. <type>pom</type>
8. <scope>import</scope>
9. </dependency>
10. </dependencies>
11. </dependencyManagement>
puis :
1. <dependency>
2. <groupId>io.quarkus</groupId>
3. <artifactId>quarkus-spring-data-jpa</artifactId>
4. </dependency>
5. <dependency>
6. <groupId>io.quarkus</groupId>
7. <artifactId>quarkus-jackson</artifactId>
8. </dependency>
9. <dependency>
10. <groupId>io.quarkus</groupId>
11. <artifactId>quarkus-resteasy-jackson</artifactId>
12. </dependency>
13. <dependency>
14. <groupId>io.quarkus</groupId>
15. <artifactId>quarkus-jdbc-postgresql</artifactId>
16. </dependency>
17. <!-- OPEN API via Swagger 2 -->
18. <dependency>
19. <groupId>io.quarkus</groupId>
20. <artifactId>quarkus-smallrye-openapi</artifactId>
21. </dependency>
22. <!-- Health Check -->
23. <dependency>
24. <groupId>io.quarkus</groupId>
25. <artifactId>quarkus-smallrye-health</artifactId>
26. </dependency>
27. <!-- Metrics -->
28. <dependency>
29. <groupId>io.quarkus</groupId>
30. <artifactId>quarkus-smallrye-metrics</artifactId>
-6-
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
31. </dependency>
32. <!-- for testing -->
33. <dependency>
34. <groupId>io.quarkus</groupId>
35. <artifactId>quarkus-junit5</artifactId>
36. <scope>test</scope>
37. </dependency>
38. <!-- for testing -->
39. <dependency>
40. <groupId>io.rest-assured</groupId>
41. <artifactId>rest-assured</artifactId>
42. <scope>test</scope>
43. </dependency>
Attention, ils sont nombreux, mais ce n'est pas rare pour des projets Maven.
1. <build>
2. <plugins>
3. <plugin>
4. <artifactId>maven-compiler-plugin</artifactId>
5. <version>3.8.1</version>
6. </plugin>
7. <plugin>
8. <groupId>io.quarkus</groupId>
9. <artifactId>quarkus-maven-plugin</artifactId>
10. <version>${quarkus-version}</version>
11. <executions>
12. <execution>
13. <goals>
14. <goal>build</goal>
15. </goals>
16. </execution>
17. </executions>
18. </plugin>
19. <plugin>
20. <artifactId>maven-resources-plugin</artifactId>
21. <version>3.1.0</version>
22. <executions>
23. <execution>
24. <id>copy-resources</id>
25. <phase>pre-integration-test</phase>
26. <goals>
27. <goal>copy-resources</goal>
28. </goals>
29. <configuration>
30. <overwrite>true</overwrite>
31. <outputDirectory>${basedir}/target/test-classes</outputDirectory>
32. <resources>
33. <resource>
34. <directory>src/test-integration/resources</directory>
35. <filtering>true</filtering>
36. </resource>
37. </resources>
38. </configuration>
39. </execution>
40. </executions>
41. </plugin>
-7-
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
-8-
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
113. <run>
114. <env>
115. <POSTGRES_USER>quarkus_tuto</POSTGRES_USER>
116. <POSTGRES_PASSWORD>quarkus_tuto</POSTGRES_PASSWORD>
117. <POSTGRES_DB>quarkus_tuto</POSTGRES_DB>
118. </env>
119. <ports>
120. <port>5432:5432</port>
121. </ports>
122. <log>
123. <prefix>PostgreSQL Server : </prefix>
124. <date>default</date>
125. <color>green</color>
126. </log>
127. <wait>
128. <tcp>
129. <mode>mapped</mode>
130. <ports>
131. <port>5432</port>
132. </ports>
133. </tcp>
134. <time>10000</time>
135. </wait>
136. </run>
137. </image>
138. </images>
139. </configuration>
140. <executions>
141. <execution>
142. <id>docker:start</id>
143. <phase>pre-integration-test</phase>
144. <goals>
145. <goal>stop</goal>
146. <goal>start</goal>
147. </goals>
148. </execution>
149. <execution>
150. <id>docker:stop</id>
151. <phase>post-integration-test</phase>
152. <goals>
153. <goal>stop</goal>
154. </goals>
155. </execution>
156. </executions>
157. </plugin>
158. </plugins>
159. </build>
Et enfin, pour atteindre le Graal du code Java compilé en binaire natif, il nous faut rajouter un petit profil Maven :
1. <profiles>
2. <profile>
3. <id>native</id>
4. <activation>
5. <property>
6. <name>native</name>
7. </property>
8. </activation>
9. <build>
10. <plugins>
11. <plugin>
12. <groupId>io.quarkus</groupId>
13. <artifactId>quarkus-maven-plugin</artifactId>
14. <version>${quarkus-plugin.version}</version>
15. <executions>
16. <execution>
17. <goals>
18. <goal>native-image</goal>
19. </goals>
20. <configuration>
21. <enableHttpUrlHandler>true</enableHttpUrlHandler>
-9-
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
22. </configuration>
23. </execution>
24. </executions>
25. </plugin>
26. <plugin>
27. <groupId>org.apache.maven.plugins</groupId>
28. <artifactId>maven-failsafe-plugin</artifactId>
29. <version>${surefire-plugin.version}</version>
30. <executions>
31. <execution>
32. <goals>
33. <goal>integration-test</goal>
34. <goal>verify</goal>
35. </goals>
36. <configuration>
37. <systemProperties>
38. <native.image.path>${project.build.directory}/
${project.build.finalName}-runner</native.image.path>
39. </systemProperties>
40. </configuration>
41. </execution>
42. </executions>
43. </plugin>
44. </plugins>
45. </build>
46. </profile>
47. </profiles>
Il est temps de coder quelques classes Quarkus dans votre IDE favori.
VI - Un simple /ping
Pour vérifier que tout va bien, on va faire un simple endpoint HTTP Rest avec JAX-RS qui va répondre à /api/ping/v1.
1. package fr.fxjavadevblog.qjg.ping;
2. import javax.ws.rs.GET;
3. import javax.ws.rs.Path;
4. import javax.ws.rs.Produces;
5. /**
6. * Simple JAX-RS endoint to check if the application is running.
7. *
8. * @author François-Xavier Robin
9. *
10. */
11. @Path("/api/ping")
12. public class PingService
13. {
14. @Path("/v1")
15. @GET
16. @Produces("text/plain")
17. public String ping()
18. {
19. return "pong";
20. }
21. }
- 10 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
- 11 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
Quakus se lance en très peu de temps alors qu'il est simplement en mode JVM classique.
Vivement le build GraalVM natif… patience.
$ curl http://localhost:8080/api/ping/v1
pong
Si on modifie le code java et qu'on le sauvegarde, il se recompile automatiquement grâce au mode dev de Quarkus.
Par exemple : on remplace return "pong"; par return "PONG"; et on sauvegarde le fichier.
$ curl http://localhost:8080/api/ping/v1
PONG
Attention avec Lombok toutefois, Quarkus ne semble pas relancer l'annotation processor et
donc il ne génère pas le bytecode de Lombok. Lien vers cette anomalie : https://github.com/
quarkusio/quarkus/issues/4224
- 12 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
Je vous conseille d'utiliser pour cela SDKMAN qui est une plate-forme pour gérer plusieurs outils de développement
présents sur votre poste en plusieurs versions et vous permet de les activer simplement et rapidement, même le
temps d'une session shell (terminal).
Dans cet exemple, j'ai choisi de mettre GraalVM en version 19.3.1 et de le déclarer comme JDK par défaut.
1. $ echo $JAVA_HOME
2. /home/robin/.sdkman/candidates/java/current
3. $ ll /home/robin/.sdkman/candidates/java/current
4. lrwxrwxrwx 1 robin robin 50 avril 2 10:25 /home/robin/.sdkman/candidates/java/current -> /
home/robin/.sdkman/candidates/java/19.3.1.r11-grl/
5. $ whereis java
6. java: /usr/bin/java /usr/lib/java /usr/share/java /home/robin/.sdkman/candidates/
java/19.3.1.r11-grl/bin/java
Pour pouvoir compiler du code Java en code natif, il faut rajouter une variable d'environnement au fichier ~/.mavenrc
(fichier à créer s'il n'existe pas).
export JAVA_HOME=/home/robin/.sdkman/candidates/java/current
export GRAALVM_HOME=$JAVA_HOME
1. $ mvn -version
2. Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
3. Maven home: /home/robin/.sdkman/candidates/maven/current
4. Java version: 11.0.6, vendor: Oracle Corporation, runtime: /home/robin/.sdkman/candidates/
java/19.3.1.r11-grl
- 13 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
1. $ gu install native-image
2. Downloading: Component catalog from www.graalvm.org
3. Processing Component: Native Image
4. Downloading: Component native-image: Native Image from github.com
5. Installing new component: Native Image (org.graalvm.native-image, version 19.3.1)
Tout est prêt pour pouvoir compiler notre application en code natif.
Il suffit de lancer Maven avec le profil native qui est présent dans le pom XML. C'est un peu long, c'est normal, mais
le résultat en vaut la chandelle.
Mais on va lancer l'application qui a été générée, classiquement, dans le répertoire target :
1. $ ./target/quarkus-tuto-0.0.1-SNAPSHOT-runner
2. __ ____ __ _____ ___ __ ____ ______
3. --/ __ \/ / / / _ | / _ \/ //_/ / / / __/
4. -/ /_/ / /_/ / __ |/ , _/ ,< / /_/ /\ \
5. --\___\_\____/_/ |_/_/|_/_/|_|\____/___/
6. 2020-04-02 17:29:01,484 INFO [io.quarkus] (main) quarkus-tuto 0.0.1-SNAPSHOT (powered by
Quarkus 1.3.1.Final) started in 0.016s. Listening on: http://0.0.0.0:8080
7. 2020-04-02 17:29:01,484 INFO [io.quarkus] (main) Profile prod activated.
- 14 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
8. 2020-04-02 17:29:01,484 INFO [io.quarkus] (main) Installed features: [agroal, cdi, hibernate-
orm, hibernate-orm-panache, hibernate-validator, jdbc-postgresql, narayana-jta, resteasy,
resteasy-jsonb, spring-data-jpa, spring-di]
Dans la configuration Maven, on a paramétré une image Docker de PostgreSQL 12 qui se lance pendant la phase
de tests d'intégration.
Pendant la phase de développement, il faut donc une instance de PostgreSQL qui va fournir la base de données de
test. Je vais utiliser encore une fois Docker pour cela.
- 15 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
44. waiting for server to start....2020-04-02 15:40:28.357 UTC [47] LOG: starting
PostgreSQL 12.2 (Debian 12.2-2.pgdg100+1) on x86_64-pc-linux-gnu, compiled by
gcc (Debian 8.3.0-6) 8.3.0, 64-bit
45. 2020-04-02 15:40:28.360 UTC [47] LOG: listening on Unix socket "/var/run/
postgresql/.s.PGSQL.5432"
46. 2020-04-02 15:40:28.383 UTC [48] LOG: database system was shut down at 2020-04-02 15:40:28
UTC
47. 2020-04-02 15:40:28.389 UTC [47] LOG: database system is ready to accept connections
48. done
49. server started
50. CREATE DATABASE
51. /usr/local/bin/docker-entrypoint.sh: ignoring /docker-entrypoint-initdb.d/*
52. 2020-04-02 15:40:28.603 UTC [47] LOG: received fast shutdown request
53. waiting for server to shut down....2020-04-02 15:40:28.605 UTC [47] LOG: aborting any active
transactions
54. 2020-04-02 15:40:28.608 UTC [47] LOG: background worker "logical replication
launcher" (PID 54) exited with exit code 1
55. 2020-04-02 15:40:28.609 UTC [49] LOG: shutting down
56. 2020-04-02 15:40:28.633 UTC [47] LOG: database system is shut down
57. done
58. server stopped
59. PostgreSQL init process complete; ready for start up.
60. 2020-04-02 15:40:28.739 UTC [1] LOG: starting PostgreSQL 12.2 (Debian 12.2-2.pgdg100+1) on
x86_64-pc-linux-gnu, compiled by gcc (Debian 8.3.0-6) 8.3.0, 64-bit
61. 2020-04-02 15:40:28.740 UTC [1] LOG: listening on IPv4 address "0.0.0.0", port 5432
62. 2020-04-02 15:40:28.740 UTC [1] LOG: listening on IPv6 address "::", port 5432
63. 2020-04-02 15:40:28.744 UTC [1] LOG: listening on Unix socket "/var/run/
postgresql/.s.PGSQL.5432"
64. 2020-04-02 15:40:28.764 UTC [65] LOG: database system was shut down at 2020-04-02 15:40:28
UTC
65. 2020-04-02 15:40:28.770 UTC [1] LOG: database system is ready to accept connections
Il faut créer un fichier application.properties comme ressource du projet Maven dans la partie Java.
1. # CDI
2. quarkus.arc.remove-unused-beans=false
3. %dev.quarkus.smallrye-openapi.path=/openapi
4. %dev.quarkus.swagger-ui.always-include=true
5. %dev.quarkus.swagger-ui.path=/openapi-ui
6. # DEV with PostgreSQL
7. %dev.quarkus.datasource.db-kind=postgresql
8. %dev.quarkus.datasource.jdbc.url=jdbc:postgresql:quarkus_tuto
9. %dev.quarkus.datasource.username=quarkus_tuto
10. %dev.quarkus.datasource.password=quarkus_tuto
11. %dev.quarkus.datasource.jdbc.max-size=8
12. %dev.us.datasource.jdbc.min-size=2
13. %dev.quarkus.hibernate-orm.log.sql=false
14. %dev.quarkus.hibernate-orm.database.generation=drop-and-create
15. %dev.quarkus.hibernate-orm.sql-load-script=import.sql
16. %dev.quarkus.log.level=INFO
17. %dev.quarkus.log.category."org.hibernate".level=INFO
18. %dev.quarkus.log.category."fr.fxjavadevblog".level=DEBUG
19. # PROD
20. %prod.quarkus.datasource.db-kind=postgresql
21. %prod.quarkus.datasource.jdbc.url=jdbc:postgresql:quarkus_tuto
22. %prod.quarkus.datasource.username=quarkus_tuto
23. %prod.quarkus.datasource.password=quarkus_tuto
24. %prod.quarkus.hibernate-orm.database.generation=drop-and-create
25. %prod.quarkus.hibernate-orm.sql-load-script=import.sql
- 16 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
Pour les tests unitaires et les tests d'intégration, nous aurons donc des fichiers application.properties différents.
Bien évidemment, il nous faut au moins une classe persistante. J'ai repris ici des exemples d'un précédent article :
1. package fr.fxjavadevblog.qjg.videogame;
2.
3. import java.io.Serializable;
4.
5. import javax.enterprise.context.Dependent;
6. import javax.inject.Inject;
7. import javax.persistence.Column;
8. import javax.persistence.Entity;
9. import javax.persistence.EnumType;
10. import javax.persistence.Enumerated;
11. import javax.persistence.Id;
12. import javax.persistence.Table;
13. import javax.persistence.Version;
14. import fr.fxjavadevblog.qjg.utils.InjectUUID;
15. import lombok.AccessLevel;
16. import lombok.EqualsAndHashCode;
17. import lombok.Getter;
18. import lombok.NoArgsConstructor;
19. import lombok.Setter;
20. import lombok.ToString;
21. @SuppressWarnings("serial")
22. // Lombok
23. @NoArgsConstructor(access = AccessLevel.PROTECTED)
24. @EqualsAndHashCode(of = "id")
25. @ToString(of = { "id", "name" })
26. // CDI Annotation
27. @Dependent
28. // JPA Annotation
29. @Entity
30. @Table(name = "VIDEO_GAME")
31. public class VideoGame implements Serializable
32. {
33. @Id
34. @Inject
35. @InjectUUID
36. @Getter
37. @Column(length = 36)
38. private String id;
39. @Getter
40. @Setter
- 17 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
1. /**
2. * Enumeration of genres of Video Games for Atari ST.
3. *
4. * @author François-Xavier Robin
5. *
6. */
7. public enum Genre
8. {
9. ARCADE, EDUCATION, FIGHTING, PINBALL, PLATFORM, REFLEXION, RPG, SHOOT_THEM_UP, SIMULATION,
SPORT;
10. }
1. package fr.fxjavadevblog.qjg;
2. import java.lang.annotation.ElementType;
3. import java.lang.annotation.Retention;
4. import java.lang.annotation.RetentionPolicy;
5. import java.lang.annotation.Target;
6. import javax.inject.Qualifier;
7. /**
8. * annotation to mark a field to be injected by CDI with a UUID.
9. *
10. * @author François-Xavier Robin
11. *
12. */
13. @Qualifier
14. @Retention(RetentionPolicy.RUNTIME)
15. @Target({ElementType.FIELD, ElementType.METHOD})
16. public @interface InjectUUID
17. {
18. }
1. package fr.fxjavadevblog.qjg.utils;
2. import java.util.UUID;
3. import javax.enterprise.context.ApplicationScoped;
4. import javax.enterprise.inject.Produces;
5. @ApplicationScoped
6. public class Producers
7. {
8. /**
9. * produces randomly generated UUID for primary keys.
10. *
11. * @return UUID as a HEXA-STRING
12. *
13. */
14. @Produces
15. @InjectUUID
16. public String produceUUIDAsString()
17. {
- 18 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
1. package fr.fxjavadevblog.qjg.videogame;
2. import java.util.List;
3. import org.springframework.data.repository.CrudRepository;
4. /**
5. * CRUD repository for the VideoGame class. Primary key is a UUID represented by a String.
6. * This repository is created by Hibernate Data JPA.
7. *
8. * @author François-Xavier Robin
9. *
10. */
11. public interface VideoGameRepository extends CrudRepository<VideoGame, String>
12. {
13. /**
14. * gets every Video Game filtered by the given Genre.
15. *
16. * @param genre
17. * genre of video game
18. * @see Genre
19. *
20. * @return
21. * a list of video games
22. */
23. List<VideoGame> findByGenre(Genre genre);
24. }
Et enfin de quoi servir le tout sur HTTP avec JAX-WS qui répond à l'URL /api/videogames/v1 :
1. package fr.fxjavadevblog.qjg.videogame;
2. import java.util.List;
3. import javax.ws.rs.BadRequestException;
4. import javax.ws.rs.GET;
5. import javax.ws.rs.Path;
6. import javax.ws.rs.PathParam;
7. import javax.ws.rs.Produces;
8. /**
9. * JAX-RS endpoint for Video Games.
10. *
11. * @author François-Xavier Robin
12. *
13. */
14. @Path("/api/videogames/v1")
15. public class VideoGameResource
16. {
17. private final VideoGameRepository videoGameRepository;
18. public VideoGameResource(VideoGameRepository videoGameRepository)
19. {
20. this.videoGameRepository = videoGameRepository;
21. }
22. @GET
23. @Produces("application/json")
24. public Iterable<VideoGame> findAll()
25. {
26. return videoGameRepository.findAll();
27. }
28. @GET
29. @Path("/genre/{genre}")
30. @Produces("application/json")
31. public List<VideoGame> findByGenre(@PathParam(value = "genre") String genre)
32. {
- 19 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
33. try
34. {
35. Genre convertedGenre = Genre.valueOf(genre.replace("-", "_").toUpperCase());
36. return videoGameRepository.findByGenre(convertedGenre);
37. }
38. catch (java.lang.IllegalArgumentException e)
39. {
40. throw new BadRequestException("Genre " + genre + "does not exist.");
41. }
42. }
43. }
Il suffit ensuite de déclencher la requête REST suivante pour obtenir tous les jeux vidéo :
1. $ curl http://localhost:8080//api/videogames/v1
2. [
3. {
4. "id": "896b9c77-4f6d-4bd6-b681-2791acfa0d51",
5. "name": "100 4 1",
6. "genre": "REFLEXION",
7. "version": 1
8. },
9. {
10. "id": "6bf157fa-bd95-46ce-bbca-58afb87ebb9b",
11. "name": "10TH FRAME",
12. "genre": "SPORT",
13. "version": 1
14. },
15. {
16. "id": "e603e430-0853-46b0-9f44-d4f662f56c51",
17. "name": "1943 : THE BATTLE OF MIDWAY",
18. "genre": "SHOOT_THEM_UP",
19. "version": 1
20. },
21. {
22. "id": "61ec5869-d9f5-497a-9ffc-8e3612892c4b",
23. "name": "1ST DIVISION MANAGER",
24. "genre": "SPORT",
25. "version": 1
26. },
27. {
28. "id": "ed1233c4-c130-49f4-b329-314a6dd957a3",
29. "name": "1ST SERVE TENNIS",
30. "genre": "SPORT",
31. "version": 1
32. },
33. {
34. "id": "85d071ca-95bc-488a-afdc-494c430f03d9",
35. "name": "20000 LEAGUES UNDER THE SEA",
36. "genre": "RPG",
37. "version": 1
38. },
39. ... etc ...
1. $ curl http://localhost:8080/api/videogames/v1/genre/SHOOT_THEM_UP
2. [
3. {
4. "id": "e603e430-0853-46b0-9f44-d4f662f56c51",
5. "name": "1943 : THE BATTLE OF MIDWAY",
6. "genre": "SHOOT_THEM_UP",
7. "version": 1
8. },
9. {
10. "id": "fa02815b-f6d2-4ba1-9f63-5c8f575d06b6",
11. "name": "AIR SUPPLY",
12. "genre": "SHOOT_THEM_UP",
13. "version": 1
14. },
- 20 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
15. {
16. "id": "07638287-8f45-4be8-a887-c57f350a9ce7",
17. "name": "ALBEDO",
18. "genre": "SHOOT_THEM_UP",
19. "version": 1
20. },
21. {
22. "id": "56417168-1e57-4197-a490-56258e5405eb",
23. "name": "ALCON",
24. "genre": "SHOOT_THEM_UP",
25. "version": 1
26. },
27. {
28. "id": "d5bd6aaa-674d-4e7f-ae8e-53118de897c6",
29. "name": "ALIEN BLAST",
30. "genre": "SHOOT_THEM_UP",
31. "version": 1
32. },
33. {
34. "id": "2589d502-4619-4728-b688-9cece2a8a3ab",
35. "name": "ALIEN BUSTERS IV",
36. "genre": "SHOOT_THEM_UP",
37. "version": 1
38. }
39. ... etc ...
Cela fonctionne, mais je trouve que ce n'est pas satisfaisant concernant les URL d'invocation pour les genres, ainsi
que le résultat JSON qui sérialise en majuscules les valeurs de l'enum. C'est normal, mais ce n'est pas très « HTTP
Friendly ».
Pour résumer le problème, les URL d'appel ainsi que le contenu du retour JSON ne respectent pas les conventions
classiques de nommage de REST.
Ce que l'on souhaite pour les URL d'appel et les retours JSON :
1. [
2. ...
3. ...
4. {
5. "id": "d5bd6aaa-674d-4e7f-ae8e-53118de897c6",
6. "name": "ALIEN BLAST",
7. "genre": "shoot-them-up",
8. "version": 1
9. },
10. ...
11. ...
12. ]
- 21 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
Mais, on ne veut pas toucher aux conventions de nommage de l'enum Genre ! C'est du Java et on doit pouvoir garder
les choses ainsi !
Il y a plein de solutions pour cela. Celle que je vais privilégier est l'usage de l'annotation @JsonProperty de Jackson
que l'on va placer sur chacune des valeurs de l'enum :
1. $ curl http://localhost:8080//api/videogames/v1/genre/SHOOT_THEM_UP
2. [
3. {
4. "id": "e603e430-0853-46b0-9f44-d4f662f56c51",
5. "name": "1943 : THE BATTLE OF MIDWAY",
6. "genre": "shoot-them-up",
7. "version": 1
8. },
9. ... etc ...
Mais le problème persiste pour l'URL ! Il faut donc créer un ParamConverter JAX-RS !
Un quoi ?
Un ParamConverter<T> est un convertisseur JAX-RS qui va être invoqué à différents moments du traitement de la
requête. Son travail est de fournir une conversion bidirectionnelle de <T> vers String et de String vers <T>.
Mais on va en créer un générique qui va aller chercher la valeur de l'annotation Jackson @JsonProperty.
1. package fr.fxjavadevblog.qjg.utils;
2.
3. import java.util.EnumSet;
4. import java.util.Optional;
5.
6. import javax.ws.rs.ext.ParamConverter;
7.
8. import org.slf4j.Logger;
9. import org.slf4j.LoggerFactory;
10.
11. import com.fasterxml.jackson.annotation.JsonProperty;
12. import com.google.common.collect.BiMap;
13. import com.google.common.collect.HashBiMap;
- 22 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
14.
15. /**
16. * Generic JAX-RS Enum converter based on the Jackson JsonProperty annotation to
17. * get the mapping.
18. *
19. * @author François-Xavier Robin
20. *
21. * @param <T>
22. */
23.
24. public class GenericEnumConverter<T extends Enum<T>> implements ParamConverter<T>
25. {
26. private static final Logger log = LoggerFactory.getLogger(GenericEnumConverter.class);
27. /**
28. * bi-directionnal Map to store enum value as key and its string representation as value.
29. * The string representation is retrieved through the JsonProperty annotation put on the
enum constant.
30. */
31. private final BiMap<T, String> biMap = HashBiMap.create();
32. /**
33. * returns a Generic converter for an enum class in the context of JAX-RS ParamConverter.
34. *
35. * @param <T>
36. * enum type
37. * @param t
38. * enum type class
39. * @return
40. * a generic converter used by JAX-RS.
41. */
42. public static <T extends Enum<T>> ParamConverter<T> of(Class<T> t)
43. {
44. return new GenericEnumConverter<>(t);
45. }
46. private GenericEnumConverter(Class<T> t)
47. {
48. log.debug("Generating conversion map for enum {}", t);
49. EnumSet.allOf(t).forEach(v -> {
50. try
51. {
52. String enumValue = v.name();
53. JsonProperty annotation =
v.getClass().getDeclaredField(enumValue).getAnnotation(JsonProperty.class);
54. // get the annotation if it exists or take the classic enum representation
55. String result =
Optional.ofNullable(annotation).map(JsonProperty::value).orElse(enumValue);
56. log.debug("Enum value {}.{} is mapped to \"{}\"", t.getSimpleName(),
v.name(), result);
57. biMap.put(v, result);
58. }
59. catch (NoSuchFieldException | SecurityException e)
60. {
61. log.error("Error while populating BiMap of enum {}", t.getClass());
62. log.error("Thrown by ", e);
63. }
64. });
65. }
66. /**
67. * returns the enum type constant from this string representation.
68. */
69. @Override
70. public T fromString(String value)
71. {
72. T returnedValue = biMap.inverse().get(value);
73. log.debug("Converting String \"{}\" to {}.{}", value, returnedValue.getClass(),
returnedValue);
74. return returnedValue;
75. }
76. /**
77. * returns the string represenation from this enum type constant.
78. */
79. @Override
80. public String toString(T t)
- 23 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
81. {
82. String returnedValue = biMap.get(t);
83. log.debug("Converting Enum {}.{} to String \"{}\"", t.getClass(), t, returnedValue);
84. return returnedValue;
85. }
86. }
• elle est instanciée en prenant une enum comme argument : ParamConverter<Genre> converter =
GenericEnumConverter.of(Genre.class); ;
• elle introspecte l'enum pendant sa construction à la recherche des annotations @JsonProperty sur chaque
valeur ;
• pour chaque valeur, elle récupère le contenu de l'annotation @JsonProperty et peuple une BiMap (Map
bidirectionnelle Guava, incluse dans Quarkus) ;
• si l'annotation n'est pas présente (on ne sait jamais), la valeur toString() de l'enum sera prise par défaut.
Ensuite, il faut enregistrer ce convertisseur automatique auprès de JAX-RS : cela se fait au moyen d'une classe qui
implémente l'interface ParamConverterProvider et d'une annotation @Provider :
1. package fr.fxjavadevblog.qjg.genre;
2. import java.lang.annotation.Annotation;
3. import java.lang.reflect.Type;
4. import javax.ws.rs.ext.ParamConverter;
5. import javax.ws.rs.ext.ParamConverterProvider;
6. import javax.ws.rs.ext.Provider;
7. import org.slf4j.Logger;
8. import org.slf4j.LoggerFactory;
9. import fr.fxjavadevblog.qjg.utils.GenericEnumConverter;
10. /**
11. * JAX-RS provider for Genre conversion. This converter is registered because of
12. * the Provider annotation.
13. *
14. * @author François-Xavier Robin
15. */
16. @Provider
17. public class GenreConverterProvider implements ParamConverterProvider
18. {
19. private final Logger log = LoggerFactory.getLogger(GenreConverterProvider.class);
20. private final ParamConverter<Genre> converter = GenericEnumConverter.of(Genre.class);
21. @SuppressWarnings("unchecked")
22. @Override
23. public <T> ParamConverter<T> getConverter(Class<T> rawType, Type genericType,
Annotation[] annotations)
24. {
25. log.debug("Registering GenreConverter");
26. return (Genre.class.equals(rawType)) ? (ParamConverter<T>) converter : null;
27. }
28. }
- 24 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
1. @GET
2. @Path("/genre/{genre}")
3. public List<VideoGame> findByGenre(@PathParam("genre") Genre genre)
4. {
5. return videoGameRepository.findByGenre(genre);
6. }
1. $ curl http://localhost:8080//api/videogames/v1/genre/shoot-them-up
2. [
3. {
4. "id": "e603e430-0853-46b0-9f44-d4f662f56c51",
5. "name": "1943 : THE BATTLE OF MIDWAY",
6. "genre": "shoot-them-up",
7. "version": 1
8. },
9. {
10. "id": "fa02815b-f6d2-4ba1-9f63-5c8f575d06b6",
11. "name": "AIR SUPPLY",
12. "genre": "shoot-them-up",
13. "version": 1
14. },
15. {
16. "id": "07638287-8f45-4be8-a887-c57f350a9ce7",
17. "name": "ALBEDO",
18. "genre": "shoot-them-up",
19. "version": 1
20. },
21. {
22. "id": "56417168-1e57-4197-a490-56258e5405eb",
23. "name": "ALCON",
24. "genre": "shoot-them-up",
25. "version": 1
26. },
27. {
28. "id": "d5bd6aaa-674d-4e7f-ae8e-53118de897c6",
29. "name": "ALIEN BLAST",
30. "genre": "shoot-them-up",
31. "version": 1
32. },
33. {
34. "id": "2589d502-4619-4728-b688-9cece2a8a3ab",
35. "name": "ALIEN BUSTERS IV",
36. "genre": "shoot-them-up",
37. "version": 1
38. }
39. ... etc.
De plus, quand on invoque l'URL avec un genre qui ne peut pas être mappé, on obtient une erreur 404. Ce
comportement est très satisfaisant.
- 25 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
XII - Tests
Ces tests sont classiquement dans le répertoire « test ». Les points particuliers sont les suivants :
Ces tests sont placés dans le répertoire « test-integration ». Les points particuliers sont les suivants :
• une image Docker PostgreSQL pour les tests d'intégration est lancée ;
• @QuarkusTest est présent sur tous les tests afin de disposer de l'environnement complet ;
• Les tests sont réalisés avec Rest Assured.
- 26 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
1. package fr.fxjavadevblog.qjg.videogame;
2. import static io.restassured.RestAssured.given;
3. import static org.hamcrest.CoreMatchers.containsString;
4. import org.junit.jupiter.api.DisplayName;
5. import org.junit.jupiter.api.Tag;
6. import org.junit.jupiter.api.Test;
7. import fr.fxjavadevblog.qjg.global.TestingGroups;
8. import io.quarkus.test.junit.QuarkusTest;
9. @QuarkusTest
10. @Tag(TestingGroups.INTEGRATION_TESTING)
11. class IT_VideoGameResource
12. {
13. public static final String ENDPOINT = "/api/videogames/v1";
14. @Test
15. @DisplayName("Get " + ENDPOINT)
16. void testGetAllVideoGames()
17. {
18. given().when()
19. .get(ENDPOINT + "/")
20. .then()
21. .statusCode(200)
22. .assertThat().body(containsString("XENON"),
23. containsString("RICK"),
24. containsString("LOTUS"));
25. }
26. }
- 27 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
- 28 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
- 29 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
148. [INFO] Tests run: 1, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 8.89 s - in
fr.fxjavadevblog.qjg.videogame.IT_VideoGameResource
149. [INFO]
150. [INFO] Results:
151. [INFO]
152. [INFO] Tests run: 2, Failures: 0, Errors: 0, Skipped: 0
153. [INFO]
154. [INFO]
155. [INFO] --- docker-maven-plugin:0.33.0:stop (docker:stop) @ quarkus-tuto ---
156. 19:29:29.455 PostgreSQL Server :2020-04-14 17:29:29.454 UTC [1] LOG: received smart
shutdown request
157. 19:29:29.460 PostgreSQL Server :2020-04-14 17:29:29.459 UTC [1] LOG: background
worker "logical replication launcher" (PID 71) exited with exit code 1
158. 19:29:29.460 PostgreSQL Server :2020-04-14 17:29:29.460 UTC [66] LOG: shutting down
159. 19:29:29.496 PostgreSQL Server :2020-04-14 17:29:29.496 UTC [1] LOG: database system is
shut down
160. [INFO] DOCKER> [postgres:12.2] "postgresql": Stop and removed container ca6a77a7d1e3 after 0
ms
161. [INFO]
162. [INFO] --- maven-failsafe-plugin:2.22.2:verify (default) @ quarkus-tuto ---
163. [INFO] ------------------------------------------------------------------------
164. [INFO] BUILD SUCCESS
165. [INFO] ------------------------------------------------------------------------
Pour générer l'image Docker de l'application native, rien de plus facile que de lancer :
- 30 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
Cette commande a réalisé une chose essentielle : elle a compilé toute l'application en une version native LINUX, quel
que soit votre environnement de travail, au moyen d'un conteneur dédié à la compilation.
Pour faire simple, un conteneur Docker ubi-quarkus-native-image:19.3.1-java11 a été récupéré puis lancé pour
compiler l'application au format LINUX, même si vous êtes sous Windows. Cela nécessite toutefois d'avoir GraalVM
installé nativement, mais cela peut-être contourné
(cf : https://quarkus.io/guides/building-native-image)
Une fois l'application compilée, il faut maintenant créer l'image du conteneur Docker. Cette création est possible en
ayant préalablement créé 2 fichiers dans /src/main/docker :
Il peut aussi exister un fichier Dockerfile.jvm mais ce n'est pas l'objet de ce tutoriel.
Dockerfile.native
1. FROM registry.access.redhat.com/ubi8/ubi-minimal
2. WORKDIR /work/
3. COPY target/*-runner /work/application
4. RUN chmod 775 /work
5. EXPOSE 8080
6. CMD ["./application", "-Dquarkus.http.host=0.0.0.0"]
.dockerignore
*
!target/*-runner
!target/*-runner.jar
- 31 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
Une fois le conteneur créé, il suffit de le lancer, en ayant lancé préalablement une instance de PostgreSQL (encore
avec Docker, comme en DEV) :
1. $ curl http://localhost:8080/api/videogames/v1/genre/rpg
2. [
3. {
4. "id": "75a9b985-c5a9-40a0-87ba-086850683bfc",
5. "name": "20000 LIEUES SOUS LES MERS",
6. "genre": "rpg",
7. "version": 1
8. },
9. {
10. "id": "2b412dd7-d090-4328-8180-869b60bbc106",
11. "name": "ADVENTURE",
12. "genre": "rpg",
13. "version": 1
14. },
15. {
16. "id": "885a3475-63c9-49f3-b120-e218ce9c9510",
17. "name": "ADVENTURER, THE",
18. "genre": "rpg",
19. "version": 1
20. },
21. {
22. "id": "a500c1a6-6008-45d4-b3f4-5b668b77499a",
23. "name": "ADVENTURES OF ROBIN HOOD, THE",
24. "genre": "rpg",
25. "version": 1
26. },
27. ... etc ...
28. ]
Quarkus embarque les extensions SmallRye Health et Metrics, qui sont les implémentations respectives de Eclipse
MicroProfile Health et Metrics.
Le simple ajout dans le pom de ces deux dépendances rend ces fonctionnalités opérationnelles :
- 32 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
Une fois l'application lancée et qu'elle est sollicitée, on peut obtenir un état de son bon fonctionnement :
1. $ curl http://localhost:8080/health
2. {
3. "status": "UP",
4. "checks": [
5. {
6. "name": "Application",
7. "status": "UP"
8. },
9. {
10. "name": "Database connections health check",
11. "status": "UP"
12. }
13. ]
14. }
On peut obtenir quelques mesures qui auront été calculées au moyen de l'annotation @Timed sur les méthodes de
la classe VideoGameResource :
- 33 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/
Tutoriel pour réduire l'empreinte serveur d'une API REST en JAVA en la compilant en code natif avec Quarkus par François-Xavier Robin
Il faut ensuite utiliser un collecteur de Metrics comme Prometheus couplé à Grafana pour
obtenir de jolis tableaux de bord.
XV - Conclusions
Quarkus est, à mon humble avis, un framework de développement de Web Services REST très intéressant sur de
nombreux aspects :
XVI - Remerciements
Nous tenons à remercier escartefigue pour sa relecture orthographique attentive de cet article et Winjerome pour
la mise au gabarit.
- 34 -
Copyright ® 2020 François-Xavier Robin. Aucune reproduction, même partielle, ne peut être faite de ce site et de l'ensemble de son contenu : textes, documents, images, etc. sans
l'autorisation expresse de l'auteur. Sinon vous encourez selon la loi jusqu'à trois ans de prison et jusqu'à 300 000 € de dommages et intérêts.
https://fxrobin.developpez.com/tutoriels/java/application-rest-quarkus-jpa-graalvm-docker/