L’année dernière, j’ai écrit l’article, « Guide de mise à niveau vers Spring Boot 3.0 pour Spring Data JPA et Querydsl, » pour la mise à niveau de Spring Boot 3.0.x. Maintenant, nous avons Spring Boot 3.2. Voyons deux problèmes que vous pourriez rencontrer lors de la mise à niveau vers Spring Boot 3.2.2.
Les technologies utilisées dans le projet SAT sont :
- Spring Boot 3.2.2 et Spring Framework 6.1.3
- Hibernate + générateur de modèle JPA 6.4.1. Final
- Spring Data JPA 3.2.2
- Querydsl 5.0.0.
Modifications
Toutes les modifications dans Spring Boot 3.2 sont décrites dans Notes de version de Spring Boot 3.2 et Nouveautés de la version 6.1 pour Spring Framework 6.1.
Les dernières modifications de Spring Boot 3.2.2 peuvent être trouvées sur GitHub.
Problèmes détectés
- A different treatment of Hibernate dependencies due to the changed
hibernate-jpamodelgen
behavior for annotation processors Unpaged
la classe a été repensée.
Commençons par les dépendances Hibernate en premier lieu.
Intégration de la Génération du Métamodèle Statique
Le plus grand changement provient de la dépendance hibernate-jpamodelgen
, qui génère un métamodèle statique metamodel. Dans Hibernate 6.3, le traitement des dépendances a été modifié afin de réduire les dépendances transitives. Spring Boot 3.2.0 a mis à niveau la dépendance hibernate-jpamodelgen
à la version 6.3 (voir Mises à niveau des dépendances). Malheureusement, la nouvelle version provoque des erreurs de compilation (voir ci-dessous).
Note: Spring Boot 3.2.2 utilisé ici utilise déjà Hibernate 6.4 avec le même comportement.
Erreur de Compilation
Avec ce changement, la compilation de notre projet (construction Maven) avec Spring Boot 3.2.2 échoue sur une erreur comme celle-ci:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 3.049 s
[INFO] Finished at: 2024-01-05T08:43:10+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.11.0:compile (default-compile) on project sat-jpa: Compilation failure: Compilation failure:
[ERROR] on the class path. A future release of javac may disable annotation processing
[ERROR] unless at least one processor is specified by name (-processor), or a search
[ERROR] path is specified (--processor-path, --processor-module-path), or annotation
[ERROR] processing is enabled explicitly (-proc:only, -proc:full).
[ERROR] Use -Xlint:-options to suppress this message.
[ERROR] Use -proc:none to disable annotation processing.
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\city\CityRepository.java:[3,41] error: cannot find symbol
[ERROR] symbol: class City_
[ERROR] location: package com.github.aha.sat.jpa.city
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\city\CityRepository.java:[3] error: static import only from classes and interfaces
...
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\country\CountryCustomRepositoryImpl.java:[4] error: static import only from classes and interfaces
[ERROR] java.lang.NoClassDefFoundError: net/bytebuddy/matcher/ElementMatcher
[ERROR] at org.hibernate.jpamodelgen.validation.ProcessorSessionFactory.<clinit>(ProcessorSessionFactory.java:69)
[ERROR] at org.hibernate.jpamodelgen.annotation.AnnotationMeta.handleNamedQuery(AnnotationMeta.java:104)
[ERROR] at org.hibernate.jpamodelgen.annotation.AnnotationMeta.handleNamedQueryRepeatableAnnotation(AnnotationMeta.java:78)
[ERROR] at org.hibernate.jpamodelgen.annotation.AnnotationMeta.checkNamedQueries(AnnotationMeta.java:57)
[ERROR] at org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity.init(AnnotationMetaEntity.java:297)
[ERROR] at org.hibernate.jpamodelgen.annotation.AnnotationMetaEntity.create(AnnotationMetaEntity.java:135)
[ERROR] at org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.handleRootElementAnnotationMirrors(JPAMetaModelEntityProcessor.java:360)
[ERROR] at org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.processClasses(JPAMetaModelEntityProcessor.java:203)
[ERROR] at org.hibernate.jpamodelgen.JPAMetaModelEntityProcessor.process(JPAMetaModelEntityProcessor.java:174)
[ERROR] at jdk.compiler/com.sun.tools.javac.processing.JavacProcessingEnvironment.callProcessor(JavacProcessingEnvironment.java:1021)
[ER...
[ERROR] at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:348)
[ERROR] Caused by: java.lang.ClassNotFoundException: net.bytebuddy.matcher.ElementMatcher
[ERROR] at java.base/java.net.URLClassLoader.findClass(URLClassLoader.java:445)
[ERROR] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:593)
[ERROR] at java.base/java.lang.ClassLoader.loadClass(ClassLoader.java:526)
[ERROR] ... 51 more
[ERROR] -> [Help 1]
[ERROR]
[ERROR] To see the full stack trace of the errors, re-run Maven with the -e switch.
[ERROR] Re-run Maven using the -X switch to enable full debug logging.
[ERROR]
[ERROR] For more information about the errors and possible solutions, please read the following articles:
[ERROR] [Help 1] http://cwiki.apache.org/confluence/display/MAVEN/MojoFailureException
Cela est dû à l’approche modifiée dans la génération du métamodèle statique annoncée dans le guide de migration Hibernate (voir Intégration de la Génération du Métamodèle Statique et le problème original HHH-17362). Leur explication pour un tel changement est la suivante:
« … dans les versions précédentes d’Hibernate ORM, vous laissiez inconsciemment fuir des dépendances de
hibernate-jpamodelgen
dans votre classpath de compilation. Avec Hibernate ORM 6.3, vous pouvez désormais rencontrer une erreur de compilation lors du traitement des annotations liée à des classes Antlr manquantes. »
Changements de dépendances
Comme on peut le voir ci-dessous sur les captures d’écran, les dépendances Hibernate ont vraiment changé.
- Spring Boot 3.1.6:
- Spring Boot 3.2.2:
Explication
Comme indiqué dans le guide de migration, nous devons modifier notre pom.xml
d’une simple dépendance Maven aux chemins des processeurs d’annotations du plugin Maven compiler (voir documentation).
Solution
Nous pouvons supprimer les dépendances Maven hibernate-jpamodelgen
et querydsl-apt
(dans notre cas) comme recommandé dans l’article précédent. À la place, pom.xml
doit définir les générateurs de modèles métamodels statiques via maven-compiler-plugin
comme ceci:
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<annotationProcessorPaths>
<path>
<groupId>org.hibernate.orm</groupId>
<artifactId>hibernate-jpamodelgen</artifactId>
<version>${hibernate.version}</version>
</path>
<path>
<groupId>com.querydsl</groupId>
<artifactId>querydsl-apt</artifactId>
<version>${querydsl.version}</version>
<classifier>jakarta</classifier>
</path>
<path>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
</path>
</annotationProcessorPaths>
</configuration>
</plugin>
</plugins>
Voir les changements liés dans le projet SAT sur GitHub.
Comme nous sommes obligés d’utiliser cette approche en raison de hibernate-jpamodelgen
, nous devons l’appliquer à toutes les dépendances liées au traitement des annotations (querydsl-apt
ou lombok
). Par exemple, lorsque lombok
n’est pas utilisé de cette manière, nous obtenons une erreur de compilation comme celle-ci:
[INFO] -------------------------------------------------------------
[ERROR] COMPILATION ERROR :
[INFO] -------------------------------------------------------------
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\city\CityService.java:[15,30] error: variable repository not initialized in the default constructor
[INFO] 1 error
[INFO] -------------------------------------------------------------
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 4.535 s
[INFO] Finished at: 2024-01-08T08:40:29+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.11.0:compile (default-compile) on project sat-jpa: Compilation failure
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\city\CityService.java:[15,30] error: variable repository not initialized in the default constructor
La même chose s’applique à querydsl-apt
. Dans ce cas, nous pouvons voir l’erreur de compilation comme celle-ci:
[INFO] ------------------------------------------------------------------------
[INFO] BUILD FAILURE
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 5.211 s
[INFO] Finished at: 2024-01-11T08:39:18+01:00
[INFO] ------------------------------------------------------------------------
[ERROR] Failed to execute goal org.apache.maven.plugins:maven-compiler-plugin:3.11.0:compile (default-compile) on project sat-jpa: Compilation failure: Compilation failure:
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\country\CountryRepository.java:[3,44] error: cannot find symbol
[ERROR] symbol: class QCountry
[ERROR] location: package com.github.aha.sat.jpa.country
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\country\CountryRepository.java:[3] error: static import only from classes and interfaces
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\country\CountryCustomRepositoryImpl.java:[3,41] error: cannot find symbol
[ERROR] symbol: class QCity
[ERROR] location: package com.github.aha.sat.jpa.city
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\country\CountryCustomRepositoryImpl.java:[3] error: static import only from classes and interfaces
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\country\CountryCustomRepositoryImpl.java:[4,44] error: cannot find symbol
[ERROR] symbol: class QCountry
[ERROR] location: package com.github.aha.sat.jpa.country
[ERROR] <SAT_PATH>\sat-jpa\src\main\java\com\github\aha\sat\jpa\country\CountryCustomRepositoryImpl.java:[4] error: static import only from classes and interfaces
[ERROR] -> [Help 1]
La raison est évidente. Nous devons appliquer tous les processeurs d’annotations en même temps. Sinon, certaines parties du code peuvent être manquantes, et nous obtenons une erreur de compilation.
Redésigné Non Paginé
Le deuxième problème mineur est lié à un changement dans la classe Unpaged
. Une sérialisation de PageImpl
par la bibliothèque Jackson a été impactée par le changement de Unpaged
d’un enum
à une class
(voir spring-projects/spring-data-commons#2987).
- Spring Boot 3.1.6:
public interface Pageable {
static Pageable unpaged() {
return Unpaged.INSTANCE;
}
...
}
enum Unpaged implements Pageable {
INSTANCE;
...
}
- Spring Boot 3.2.2:
public interface Pageable {
static Pageable unpaged() {
return unpaged(Sort.unsorted());
}
static Pageable unpaged(Sort sort) {
return Unpaged.sorted(sort);
}
...
}
final class Unpaged implements Pageable {
private static final Pageable UNSORTED = new Unpaged(Sort.unsorted());
...
}
Lorsque new PageImpl<City>(cities)
est utilisé (comme nous avions l’habitude de l’utiliser), alors cette erreur est lancée:
2024-01-11T08:47:56.446+01:00 WARN 5168 --- [sat-elk] [ main] .w.s.m.s.DefaultHandlerExceptionResolver : Resolved [org.springframework.http.converter.HttpMessageNotWritableException: Could not write JSON: (was java.lang.UnsupportedOperationException)]
MockHttpServletRequest:
HTTP Method = GET
Request URI = /api/cities/country/Spain
Parameters = {}
Headers = []
Body = null
Session Attrs = {}
Handler:
Type = com.github.aha.sat.elk.city.CityController
Method = com.github.aha.sat.elk.city.CityController#searchByCountry(String, Pageable)
Async:
Async started = false
Async result = null
Resolved Exception:
Type = org.springframework.http.converter.HttpMessageNotWritableException
La solution de contournement consiste à utiliser le constructeur avec tous les attributs comme suit:
new PageImpl<City>(cities, ofSize(PAGE_SIZE), cities.size())
Au lieu de:
new PageImpl<City>(cities)
Note: Cela devrait être corrigé dans Spring Boot 3.3 (voir ce commentaire d’issue).
Conclusion
Cet article a abordé les problèmes rencontrés lors de la mise à niveau vers la dernière version de Spring Boot 3.2.2 (au moment de la rédaction de cet article). L’article a commencé par la gestion des processeurs d’annotations en raison du changement de gestion des dépendances Hibernate. Ensuite, le changement dans la classe Unpaged
et la solution de contournement pour l’utilisation de PageImpl
a été expliquée.
Toutes les modifications (avec d’autres changements) peuvent être vues dans PR #64. Le code source complet démontré ci-dessus est disponible dans mon dépôt GitHub.
Source:
https://dzone.com/articles/upgrade-guide-to-spring-boot-32-for-spring-data-jp