Guide de mise à niveau vers Spring Boot 3.0 pour Spring Data JPA et Querydsl

L’année dernière, j’ai écrit deux articles sur JPA Criteria et Querydsl (voir les articles Introduction et Metamodel). Depuis la fin de l’année dernière, il y a eu une nouvelle mise à jour majeure de Spring Boot 3. Cette mise à jour est basée sur Spring Framework 6 avec plusieurs changements significatifs et problèmes que nous devons prendre en compte lors de la mise à niveau.

Le but de cet article est de mettre en évidence ces changements lors de la mise à niveau du projet sat-jpa (projet SAT). Les technologies utilisées ici sont :

  1. Spring Boot 3.0.2,
  2. Hibernate 6.1.6.Final
  3. Spring Data JPA 3.0.1 et
  4. Querydsl 5.0.0.

Spring Framework 6.0.4

Spring Framework 6 comporte de nombreux changements (voir What’s New in Spring Framework 6.x), les changements clés sont :

  1. Passage de la base Java à Java 17 (toujours la dernière version Java LTS au moment de la rédaction de cet article) — c’est-à-dire, c’est la version minimale de Java que nous devons utiliser.
  2. Passage de la base Jakarta à Jakarta EE 9+.

En dehors de cela, il y a juste un petit changement dans Spring MVC utilisé dans le projet SAT.

Spring MVC 6.0.4

Toutes les méthodes de la classe ResponseEntityExceptionHandler ont modifié leurs signatures. Le paramètre status a été modifié du type HttpStatus au type HttpStatusCode (voir le changement dans la classe CityExceptionHandler).

HttpStatus dans Spring MVC 5

Java

 

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception,
		HttpHeaders headers, HttpStatus status, WebRequest request) {
	return buildResponse(BAD_REQUEST, exception);
}

HttpStatusCode dans Spring MVC 6

Java

 

@Override
protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException exception, 
        HttpHeaders headers, HttpStatusCode status, WebRequest request) {
	return buildResponse(BAD_REQUEST, exception);
}

Spring Boot 3.0.2

Spring Boot 3 comporte de nombreux changements (voir Notes de version Spring Boot 3.0) ; les plus importants sont ceux-ci :

  • Java 17 (défini par le Framework Spring).
  • Augmentation au Framework Spring 6 (voir ci-dessus).
  • Augmentez jusqu’à Hibernate 6 (voir ci-dessous).
  • Migration des dépendances JavaEE vers Jakarta EE — ce n’est pas important dans notre cas car nous ne nous appuyons pas sur Java d’entreprise, mais cela peut affecter de nombreuses dépendances (par exemple, API servlet, validation, persistance, JMS, etc.).
  • Petit changement dans Spring MVC 6 concernant la classe ResponseEntityExceptionHandler (voir la partie suivante).

Commençons par les changements simples de Jakarta EE. Ainsi, nous pourrons nous concentrer sur la persistance ensuite.

Dépendances Jakarta EE

Le changement majeur est la migration des dépendances Java EE vers Jakarta EE. Le Spring Framework 6 a établi la base comme Jakarta EE 9 (voir Quoi de neuf dans le Spring Framework 6.x), mais Spring Boot 3 utilise déjà Jakarta EE 10 (voir Notes de version de Spring Boot 3.0) pour de nombreuses API (par exemple, Servlet ou JPA — pour citer quelques technologies).

En conséquence, toutes les classes utilisant une autre classe du paquetage jakarta doivent passer à la même classe du paquetage javax à la place (voir, par exemple, les annotations PostConstruct ou Entity).

Imports Javax

Java

 

import javax.annotation.PostConstruct;
import javax.persistence.Entity;

Imports Jakarta

Java

 

import jakarta.annotation.PostConstruct;
import jakarta.persistence.Entity;

Hibernate 6.1.6

Un autre changement majeur dans Spring Boot 3 est la mise à niveau de Hibernate 5.6 à Hibernate 6.1. Les détails sur Hibernate 6.1 peuvent être trouvés ici ou dans les notes de version.

Honnêtement, je n’ai pas prêté attention à ce changement jusqu’à ce que je doive corriger un test échouant en raison d’une taille de résultat différente (voir le correctif dans la classe CountryRepositoryCustomTests). L’implémentation avec le nouveau Hibernate 6 renvoie moins d’entités qu’auparavant.

Il est important de mentionner deux changements ici suite à cette enquête. Commençons par le logging en premier.

Enregistrement

Les enregistreurs Hibernate ont été modifiés de org.hibernate.type à org.hibernate.orm.jdbc (voir cette référence et cette référence).

Note : toutes les options de configuration disponibles peuvent être trouvées dans la classe org.hibernate.cfg.AvailableSettings.

Hibernate 5

Il y avait un seul enregistreur pour les valeurs cachées et extraites.

Properties files

 

logging.level.org.hibernate.type.descriptor.sql.BasicBinder=TRACE

Hibernate 6

Hibernate 6 a modifié le package principal et les a divisés en deux enregistreurs différents afin de distinguer l’opération -> quel valeur doit être enregistrée.

Properties files

 

logging.level.org.hibernate.orm.jdbc.bind=trace
logging.level.org.hibernate.orm.jdbc.extract=trace

Modèle de requête sémantique

Comme le logging a été corrigé, il a été confirmé que Hibernate extrait vraiment deux enregistrements de la base de données :

Plain Text

 

2023-01-25T08:40:18.819+01:00  INFO 6192 --- [           main] c.g.a.s.j.c.CountryRepositoryCustomTests : Started CountryRepositoryCustomTests in 4.678 seconds (process running for 5.745)
Hibernate: select c2_0.id,c2_0.name from city c1_0 join country c2_0 on c2_0.id=c1_0.country_id where c1_0.name like ? escape '!' and c1_0.state like ? escape '!'
2023-01-25T08:40:19.221+01:00 TRACE 6192 --- [           main] org.hibernate.orm.jdbc.extract           : extracted value ([1] : [BIGINT]) - [3]
2023-01-25T08:40:19.222+01:00 TRACE 6192 --- [           main] org.hibernate.orm.jdbc.extract           : extracted value ([2] : [VARCHAR]) - [USA]
2023-01-25T08:40:19.240+01:00 TRACE 6192 --- [           main] org.hibernate.orm.jdbc.extract           : extracted value ([1] : [BIGINT]) - [3]
2023-01-25T08:40:19.241+01:00 TRACE 6192 --- [           main] org.hibernate.orm.jdbc.extract           : extracted value ([2] : [VARCHAR]) - [USA]

Cependant, le test reçoit uniquement une seule entité de Hibernate, comme vous pouvez le voir dans ces captures d’écran de débogage :

Le comportement modifié est dû au nouveau Modèle de requête sémantique avec déduplication automatique (voir Modèle de requête sémantique partie) introduit avec Hibernate 6 (voir la ligne 178 dans la classe org.hibernate.sql.results.spi.ListResultsConsumer). Hibernate 6 renvoie maintenant le résultat déduplicué.

Générateur JPA Hibernate

La dépendance Maven Hibernate Jpamodelgen gérée par Spring Boot Dependencies a été déplacée du paquet org.hibernate au paquet org.hibernate.orm. Voir :

Spring Boot 2.7.5

XML

 

<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>

Spring Boot 3.0.2

XML

 

<dependency>
	<groupId>org.hibernate.orm</groupId>
	<artifactId>hibernate-jpamodelgen</artifactId>
</dependency>

Liquibase

Pour terminer les dépendances de persistance principales, Liquibase est passé de la version 4.9.1 à 4.17.2. Il n’y a pas de différence significative, sauf pour l’utilisation de la dépendance JAX-B. La dépendance devrait utiliser JAX-B de Jakarta au lieu de Javax (voir le référence suivante).

Spring Boot 2.7.5

XML

 

<dependency>
	<groupId>org.liquibase</groupId>
	<artifactId>liquibase-core</artifactId>
</dependency>

Spring Boot 3.0.2

XML

 

<dependency>
	<groupId>org.liquibase</groupId>
	<artifactId>liquibase-core</artifactId>
	<exclusions>
		<exclusion> <!-- due to SB 3.0 switch to Jakarta -->
			<groupId>javax.xml.bind</groupId>
			<artifactId>jaxb-api</artifactId>
		</exclusion>
	</exclusions>
</dependency>
<dependency>
	<groupId>jakarta.xml.bind</groupId>
	<artifactId>jakarta.xml.bind-api</artifactId>
</dependency>

Spring Data JPA 3.0.1

Spring Boot 3.0.2 dépend de la Spring Data Release Train 2022.0.1 (voir Notes de publication de Spring Data 2022.0 – Release Turing), où Spring Data JPA 3.0.1 est utilisé avec ces changements clés (voir les notes de publication) :

  1. Basculer la base Java vers Java 17,
  2. Basculer la base Jakarta vers Jakarta EE 10 et
  3. Augmenter vers Hibernate 6

Note : la version précédemment utilisée (dans notre cas) était la version 2.7.5.

Querydsl 5.0.0

La version Querydsl n’a pas été modifiée, mais elle a été impactée de manière similaire à Liquibase. Les dépendances doivent être utilisées à partir de Jakarta au lieu de Javax. Par conséquent, la dépendance Querydsl doit utiliser le classifier jakarta au lieu de l’ancien classifier jpa (voir ce référence).

Spring Boot 2.7.5

XML

 

<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-jpa</artifactId>
</dependency>
<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-apt</artifactId>
	<version>${querydsl.version}</version>
	<classifier>jpa</classifier>
	<scope>provided</scope>
</dependency>

Spring Boot 3.0.2

XML

 

<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-jpa</artifactId>
	<version>${querydsl.version}</version>
	<classifier>jakarta</classifier>
</dependency>
<dependency>
	<groupId>com.querydsl</groupId>
	<artifactId>querydsl-apt</artifactId>
	<scope>provided</scope>
	<version>${querydsl.version}</version>
	<classifier>jakarta</classifier>
</dependency>

Conclusion

Cet article a couvert la mise à niveau vers la dernière version de Spring Boot 3.0.2 pour JPA et Querydsl (au moment de la rédaction de cet article). L’article a commencé par les changements du Spring Framework et de Spring Boot. Ensuite, tous les changements apportés à Hibernate et aux technologies connexes ont été abordés. En fin de compte, nous avons mentionné les légères modifications liées à Spring Data 3.0.1 et Querydsl 5.0.0.

Le code source complet démontré ci-dessus est disponible dans mon GitHub dépôt.

Note : il y a également un article précédent, Guide de mise à niveau vers Spring Data Elasticsearch 5.0, consacré à une mise à niveau similaire d’Elasticsearch avec Spring Boot 3.

Source:
https://dzone.com/articles/upgrade-guide-to-spring-boot-3-for-spring-data-jpa-3-and-querydsl-5