Upgradegids voor Spring Boot 3.0 met Spring Data JPA en Querydsl

Vorig jaar schreef ik twee artikelen over JPA Criteria en Querydsl (zie Inleiding en Metamodel artikelen). Sinds het einde van vorig jaar is er een nieuwe grote release van Spring Boot 3. Deze release is gebaseerd op Spring Framework 6 met verschillende belangrijke wijzigingen en kwesties die we moeten overwegen bij het upgraden.

Het doel van dit artikel is om deze wijzigingen te benadrukken bij het upgraden van het sat-jpa project (SAT project). De hier gebruikte technologieën zijn:

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

Spring Framework 6.0.4

Spring Framework 6 heeft veel wijzigingen (zie Wat is nieuw in Spring Framework 6.x), de belangrijkste wijzigingen zijn:

  1. Switch Java baseline naar Java 17 (nog steeds de laatste Java LTS op het moment van het schrijven van dit artikel) — dat wil zeggen, het is de minimale Java-versie die we moeten gebruiken.
  2. Switch Jakarta baseline naar Jakarta EE 9+.

Daarnaast is er slechts één kleine verandering in Spring MVC die in het SAT-project wordt gebruikt.

Spring MVC 6.0.4

Alle methoden in de ResponseEntityExceptionHandler klasse hebben hun signaturen gewijzigd. Het status argument is gewijzigd van HttpStatus naar HttpStatusCode type (zie de wijziging in de CityExceptionHandler klasse).

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 bevat veel wijzigingen (zie Spring Boot 3.0 Release Notes); de belangrijkste zijn deze:

  • Java 17 (gedefinieerd door het Spring Framework).
  • Opfris naar Spring Framework 6 (zie boven).
  • Bump up naar Hibernate 6 (zie hieronder).
  • Migratie van JavaEE naar Jakarta EE afhankelijkheden — dit is niet belangrijk in ons geval, aangezien we hier niet vertrouwen op enterprise Java, maar het kan veel afhankelijkheden beïnvloeden (bijv. servlet API, validatie, persistentie, JMS, enz.).
  • Kleine wijziging in Spring MVC 6 in de ResponseEntityExceptionHandler klasse (zie het volgende deel).

Laten we beginnen met de eenvoudige Jakarta EE wijzigingen. Zo kunnen we daarna focussen op persistentie.

Jakarta EE Afhankelijkheden

De belangrijkste wijziging is de migratie van Java EE naar Jakarta EE afhankelijkheden. Spring Framework 6 stelt de basislijn op Jakarta EE 9 (zie Wat is nieuw in Spring Framework 6.x), maar Spring Boot 3 gebruikt al Jakarta EE 10 (zie Spring Boot 3.0 Release Notes) voor veel API’s (bijv. Servlet of JPA — om slechts enkele technologieën te noemen).

Als gevolg hiervan moeten alle klassen die een andere klasse gebruiken uit het jakarta pakket overschakelen naar dezelfde klasse uit het javax pakket (zie bijvoorbeeld PostConstruct of Entity annotaties).

Javax Importen

Java

 

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

Jakarta Importen

Java

 

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

Hibernate 6.1.6

Een ander grote verandering in Spring Boot 3 is de upgrade van Hibernate 5.6 naar Hibernate 6.1. Meer informatie over Hibernate 6.1 is te vinden hier of in de release notes.

Eerlijk gezegd heb ik niet opgelet bij deze verandering totdat ik een falende test moest repareren vanwege een ander resultaat aantal (zie de fix in de CountryRepositoryCustomTests klasse). De implementatie met de nieuwe Hibernate 6 geeft minder entiteiten terug dan voorheen.

Het is vermeldenswaardig twee veranderingen te noemen hier op basis van dit onderzoek. Laten we eerst beginnen met logging.

Logboekregistratie

De Hibernate loggers zijn gewijzigd van org.hibernate.type naar org.hibernate.orm.jdbc (zie deze referentie en deze referentie).

Opmerking: alle beschikbare configuratie-items kunnen worden gevonden in de org.hibernate.cfg.AvailableSettings klasse.

Hibernate 5

Er was een enkele logger voor de gebonden en geëxtraheerde waarden.

Properties files

 

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

Hibernate 6

Hibernate 6 heeft de hoofdmap gewijzigd en ze gesplitst in twee verschillende loggers om de operatie te onderscheiden -> welke waarde moet worden geregistreerd.

Properties files

 

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

Semantisch Query Model

Na het repareren van de logboekregistratie, is bevestigd dat Hibernate echt twee records uit de DB extraheert:

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]

Echter, de test ontvangt slechts één entiteit van Hibernate, zoals te zien is in deze debugschermafbeeldingen:

Het gewijzigde gedrag wordt veroorzaakt door het nieuwe Semantisch Query Model met automatische deduplicatie (zie Semantisch Query Model deel) geïntroduceerd met Hibernate 6 (zie regel 178 in de org.hibernate.sql.results.spi.ListResultsConsumer klasse). Hibernate 6 retourneert nu het gededupeerde resultaat.

Hibernate JPA Generator

De Hibernate Jpamodelgen maven-afhankelijkheid, beheerd door Spring Boot Dependencies, is verplaatst van de org.hibernate naar de org.hibernate.orm package. Zie:

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

Om de kern persistentiediepende afhankelijkheden af te ronden, is Liquibase bijgewerkt van versie 4.9.1 naar 4.17.2. Er is geen significant verschil behalve het gebruik van de JAX-B afhankelijkheid. De afhankelijkheid zou JAX-B van Jakarta in plaats van Javax moeten gebruiken (zie de volgende referentie).

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 is afhankelijk van Spring Data Release Train 2022.0.1 (zie Spring Data 2022.0 – Turing Release Notes), waar Spring Data JPA 3.0.1 wordt gebruikt met deze belangrijke wijzigingen (zie de release notes):

  1. Schakel Java baseline over naar Java 17,
  2. Schakel Jakarta baseline over naar Jakarta EE 10 en
  3. Opschonen naar Hibernate 6

Opmerking: de eerder gebruikte versie (in ons geval) was de 2.7.5-versie.

Querydsl 5.0.0

De Querydsl-versie is niet gewijzigd, maar is op een vergelijkbare manier beïnvloed als Liquibase. De afhankelijkheden moeten worden gebruikt van Jakarta in plaats van Javax. Daarom moet de Querydsl-afhankelijkheid de jakarta classificatie gebruiken in plaats van de oude jpa classificatie (zie deze referentie).

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>

Conclusie

Dit artikel behandelt de upgrade naar de nieuwste Spring Boot 3.0.2 voor JPA en Querydsl (op het moment van het schrijven van dit artikel). Het artikel begon met Spring Framework en Spring Boot-wijzigingen. Vervolgens zijn alle wijzigingen in Hibernate en gerelateerde technologieën behandeld. Uiteindelijk hebben we de kleine wijzigingen met betrekking tot Spring Data 3.0.1 en Querydsl 5.0.0 genoemd.

De volledige broncode die hierboven wordt getoond, is beschikbaar in mijn GitHub repository.

Opmerking: er is ook een eerdere artikel, Upgradegids voor Spring Data Elasticsearch 5.0, gewijd aan een vergelijkbare upgrade van Elasticsearch met Spring Boot 3.

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