Upgrade-Anleitung zu Spring Boot 3.0 für Spring Data JPA und Querydsl

Letztes Jahr habe ich zwei Artikel über JPA Criteria und Querydsl geschrieben (siehe Einführung und Metamodell Artikel). Seit Ende letzten Jahres gibt es eine neue Hauptversion von Spring Boot 3. Diese Version basiert auf dem Spring Framework 6 mit mehreren bedeutenden Änderungen und Problemen, die wir bei der Aktualisierung berücksichtigen sollten.

Ziel dieses Artikels ist es, diese Änderungen bei der Aktualisierung des sat-jpa Projekts (SAT-Projekt) hervorzuheben. Die hier verwendeten Technologien sind:

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

Spring Framework 6.0.4

Das Spring Framework 6 hat viele Änderungen (siehe Was ist neu im Spring Framework 6.x), die wichtigsten Änderungen sind:

  1. Basis-Java auf Java 17 umschalten (immer noch die letzte Java LTS zum Zeitpunkt des Schreibens dieses Artikels) — das heißt, es ist die minimale Java-Version, die wir verwenden müssen.
  2. Basis-Jakarta auf Jakarta EE 9+ umschalten.

Außerdem gibt es nur eine kleine Änderung im in SAT-Projekt verwendeten Spring MVC.

Spring MVC 6.0.4

Alle Methoden in der Klasse ResponseEntityExceptionHandler haben ihre Signaturen geändert. Das status-Argument wurde von HttpStatus in den Typ HttpStatusCode geändert (siehe die Änderung in der Klasse CityExceptionHandler).

HttpStatus in Spring MVC 5

Java

 

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

HttpStatusCode in 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 bringt viele Änderungen mit sich (siehe Spring Boot 3.0 Release Notes); die wichtigsten sind:

  • Java 17 (festgelegt durch das Spring Framework).
  • Spring Framework 6 aufstocken (siehe oben).
  • Erhöhen Sie auf Hibernate 6 (siehe unten).
  • Migration von JavaEE zu Jakarta EE-Abhängigkeiten — es ist in unserem Fall nicht wichtig, da wir nicht auf enterprise Java angewiesen sind, kann es jedoch viele Abhängigkeiten betreffen (z.B. Servlet-API, Validierung, Persistenz, JMS usw.).
  • Kleine Änderung in Spring MVC 6 im ResponseEntityExceptionHandler-Klasse (siehe nächster Abschnitt).

Beginnen wir mit den einfachen Jakarta EE-Änderungen. So können wir uns danach auf die Persistenz konzentrieren.

Jakarta EE Abhängigkeiten

Der wesentliche Wechsel ist die Migration von Java EE zu Jakarta EE-Abhängigkeiten. Spring Framework 6 setzt die Grundlage als Jakarta EE 9 (siehe Was ist neu in Spring Framework 6.x), aber Spring Boot 3 verwendet bereits Jakarta EE 10 (siehe Spring Boot 3.0 Release Notes) für viele APIs (z.B. Servlet oder JPA — um nur einige Technologien zu nennen).

Folglich müssen alle Klassen, die eine andere Klasse aus dem jakarta Paket verwenden, stattdessen zur gleichen Klasse aus dem javax Paket wechseln (siehe z.B. PostConstruct oder Entity Annotationen).

Javax Importe

Java

 

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

Jakarta Importe

Java

 

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

Hibernate 6.1.6

Ein weiterer wichtiger Wandel in Spring Boot 3 ist die Aktualisierung von Hibernate 5.6 auf Hibernate 6.1. Details zu Hibernate 6.1 finden Sie hier oder in den Versionshinweisen.

Ehrlich gesagt, habe ich diese Änderung erst bemerkt, als ich ein fehlendes Test aufgrund einer anderen Ergebnisgröße beheben musste (siehe das Fix in der CountryRepositoryCustomTests Klasse). Die Implementierung mit dem neuen Hibernate 6 gibt weniger Entitäten zurück als zuvor.

Zwei Änderungen sind hier aufgrund dieser Untersuchung erwähnenswert. Fangen wir zunächst mit dem Logging an.

Logging

Die Hibernate-Logger wurden von org.hibernate.type auf org.hibernate.orm.jdbc geändert (siehe diesen Verweis und diesen Verweis).

Hinweis: Alle verfügbaren Konfigurationsoptionen finden Sie im org.hibernate.cfg.AvailableSettings-Klassen.

Hibernate 5

Es gab einen einzelnen Logger für die gebundenen und extrahierten Werte.

Properties files

 

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

Hibernate 6

Hibernate 6 hat das Hauptpaket geändert und in zwei verschiedene Logger aufgespalten, um die Operation zu unterscheiden -> welcher Wert geloggt werden sollte.

Properties files

 

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

Semantische Abfrage-Modell

Nachdem das Logging behoben wurde, wurde bestätigt, dass Hibernate tatsächlich zwei Datensätze aus der DB extrahiert:

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]

Allerdings erhält der Test nur ein einzelnes Entitäts aus Hibernate, wie man in diesen Debugging-Screenshots sehen kann:

Die geänderte Verhaltensweise wird durch das neue Semantische Abfrage-Modell mit automatischer Deduplizierung (siehe Semantische Abfrage-Modell Teil) eingeführt mit Hibernate 6 (siehe Zeile 178 in org.hibernate.sql.results.spi.ListResultsConsumer-Klasse). Hibernate 6 gibt nun das deduplizierte Ergebnis zurück.

Hibernate JPA Generator

Die Hibernate Jpamodelgen-Maven-Abhängigkeit, die von Spring Boot Dependencies verwaltet wird, wurde von dem Paket org.hibernate in das Paket org.hibernate.orm verschoben. Siehe:

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

Um die Kernpersistenzabhängigkeiten abzuschließen, wurde die Liquibase von Version 4.9.1 auf 4.17.2 aktualisiert. Es gibt keine signifikanten Unterschiede, außer der Verwendung der JAX-B-Abhängigkeit. Die Abhängigkeit sollte JAX-B von Jakarta anstelle von Javax verwenden (siehe den folgenden Verweis).

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 hängt von der Spring Data Release Train 2022.0.1 ab (siehe Spring Data 2022.0 – Turing Release Notes), wobei Spring Data JPA 3.0.1 mit diesen wichtigen Änderungen verwendet wird (siehe die Release-Notes):

  1. Schaltet die Java-Basis auf Java 17 um,
  2. Schaltet die Jakarta-Basis auf Jakarta EE 10 und
  3. Aufwärtsschub auf Hibernate 6

Hinweis: Die zuvor verwendete Version (in unserem Fall) war die 2.7.5-Version.

Querydsl 5.0.0

Die Querydsl-Version wurde nicht geändert, aber sie wurde auf ähnliche Weise wie Liquibase betroffen. Die Abhängigkeiten müssen stattdessen von Jakarta anstelle von Javax verwendet werden. Daher muss die Querydsl-Abhängigkeit stattdessen den jakarta-Klassifikator anstelle des alten jpa-Klassifikators verwenden (siehe diesen Verweis).

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>

Schlussfolgerung

Dieser Artikel behandelt das Upgrade auf die neueste Spring Boot 3.0.2-Version für JPA und Querydsl (bei Abfassung dieses Artikels). Der Artikel beginnt mit Spring Framework- und Spring Boot-Änderungen. Danach wurden alle Änderungen an Hibernate und verwandten Technologien behandelt. Zum Schluss erwähnten wir die geringfügigen Änderungen im Zusammenhang mit Spring Data 3.0.1 und Querydsl 5.0.0.

Der oben gezeigte vollständige Quellcode ist in meinem GitHub-Repository verfügbar.

Hinweis: Es gibt auch einen vorhergehenden Artikel, Upgrade-Leitfaden für Spring Data Elasticsearch 5.0, der sich einem ähnlichen Upgrade von Elasticsearch mit Spring Boot 3 widmet.

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