Spring Data JPAおよびQuerydslのためのSpring Boot 3.0へのアップグレードガイド

昨年、私はJPA CriteriaとQuerydslに関する二つの記事を書いた(はじめにおよびメタモデルの記事を参照)。昨年末から、Spring Bootの新しいメジャーバージョン3が登場しています。このリリースは、Spring Framework 6に基づいており、アップグレード時に考慮すべき重要な変更や問題がいくつかあります。

本記事の目的は、sat-jpaプロジェクト(SATプロジェクト)をアップグレードする際にこれらの変更を強調することです。ここで使用されている技術は以下の通りです:

  1. Spring Boot 3.0.2、
  2. Hibernate 6.1.6.Final、
  3. Spring Data JPA 3.0.1、そして
  4. Querydsl 5.0.0。

Spring Framework 6.0.4

Spring Framework 6には多くの変更があります(Spring Framework 6.xの新機能を参照)、主な変更点は:

  1. JavaベースラインをJava 17に切り替える(この記事を書いている時点での最新のJava LTS)—つまり、使用しなければならない最小のJavaバージョンです。
  2. JakartaベースラインをJakarta EE 9+に切り替える。

その他、SATプロジェクトで使用されているSpring MVCにはごく小さな変更があります。

Spring MVC 6.0.4

ResponseEntityExceptionHandler クラス内のすべてのメソッドのシグネチャが変更されました。status 引数が HttpStatus から HttpStatusCode 型に変更されました(CityExceptionHandler クラスの変更を参照)。

Spring MVC 5 の HttpStatus

Java

 

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

Spring MVC 6 の HttpStatusCode

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 には多くの変更があります(Spring Boot 3.0 Release Notes を参照); 最も重要なのは次のものです:

  • Spring Framework によって定義された Java 17。
  • 上記を参照して、Spring Framework 6 へのアップデート。
  • Hibernate 6 へのアップグレード(下を参照)。
  • JavaEEからJakarta EEへの依存関係の移行 — 私たちの場合、エンタープライズJavaに依存していないため重要ではありませんが、多くの依存関係に影響を与える可能性があります(例:サーブレットAPI、バリデーション、永続化、JMSなど)。
  • Spring MVC 6におけるResponseEntityExceptionHandlerクラスの小幅な変更(次の部分を参照)。

まずはシンプルなJakarta EEの変更から始め、その後永続化に焦点を当てましょう。

Jakarta EE依存関係

大きな変化は、Java EEからJakarta EEへの依存関係の移行です。Spring Framework 6はJakarta EE 9をベースラインとして設定しています(Spring Framework 6.xの新機能を参照)が、Spring Boot 3はすでに多くのAPI(例:サーブレットやJPAなどの技術)に対してJakarta EE 10を使用しています(Spring Boot 3.0リリースノートを参照)。

その結果、jakartaパッケージの別のクラスを使用するすべてのクラスは、代わりにjavaxパッケージの同じクラスに切り替える必要があります(例えば、PostConstructEntityアノテーションを参照)。

Javaxインポート

Java

 

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

Jakartaインポート

Java

 

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

Hibernate 6.1.6

Spring Boot 3における別の主要な変更点は、Hibernate 5.6からHibernate 6.1へのアップグレードです。Hibernate 6.1の詳細については、こちらまたはリリースノート内をご覧ください。

正直なところ、この変更に注意を払っていなかったのは、結果のサイズが異なるために失敗したテストを修正しなければならなかったときでした(CountryRepositoryCustomTestsクラスの修正を参照)。新しいHibernate 6の実装では、以前よりも少ないエンティティが返されます。

この調査に基づく2つの変更について触れる価値があります。まずはロギングから始めましょう。

ロギング

Hibernateのロガーはorg.hibernate.typeからorg.hibernate.orm.jdbcに変更されました(この参照この参照を参照してください)。

注: 利用可能なすべての設定項目はorg.hibernate.cfg.AvailableSettingsクラスで確認できます。

Hibernate 5

バインドおよび抽出された値に対して単一のロガーが使用されていました。

Properties files

 

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

Hibernate 6

Hibernate 6はメインパッケージを変更し、操作を区別するために2つの異なるロガーに分割しました→どの値をログに記録すべきか。

Properties files

 

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

セマンティッククエリモデル

ロギングが固定されたことで、Hibernateが実際にDBから2つのレコードを抽出することが確認されました。

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]

しかし、テストはHibernateから単一のエンティティのみを受け取ります。これらのデバッグスクリーンショットで確認できます。

この変更された動作は、Hibernate 6で導入された新しいセマンティッククエリモデルと自動的重複除去セマンティッククエリモデルの部分を参照)によるものです(org.hibernate.sql.results.spi.ListResultsConsumerクラスの178行を参照)。Hibernate 6は現在、重複除去された結果を返します。

Hibernate JPAジェネレータ

Hibernate Jpamodelgenのmaven依存関係はSpring Boot Dependenciesによって管理され、org.hibernateからorg.hibernate.ormパッケージに移動されました。参照:

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

コア永続性依存関係の完了のため、Liquibaseはバージョン4.9.1から4.17.2にアップグレードされました。JAX-B依存関係の使用が異なるだけで、それ以外は大きな違いはありません。依存関係はJakartaのJAX-Bを使用するべきであり、Javaxではないことに注意してください(以下の参照を参照)。

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はSpring Dataリリーストレイン2022.0.1に依存しています(Spring Data 2022.0 – チューリングリリースノートを参照)。ここでSpring Data JPA 3.0.1は、以下の主要変更点があります(リリースノートを参照):

  1. JavaベースラインをJava 17に切り替え、
  2. JakartaベースラインをJakarta EE 10に切り替え、
  3. Hibernate 6へのアップグレード

注: 以前使用していたバージョン(私たちの場合)は2.7.5でした。

Querydsl 5.0.0

Querydslのバージョンは変更されませんでしたが、Liquibaseと同様に影響を受けました。依存関係はJavaxではなくJakartaから使用する必要があります。したがって、Querydslの依存関係は古いjpaクラスタリファイアではなくjakartaクラスタリファイアを使用する必要があります(このリファレンスを参照)。

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>

結論

この記事では、JPAおよびQuerydslの最新バージョンであるSpring Boot 3.0.2へのアップグレードについて説明しました(この記事を書いている時点で)。記事はSpring FrameworkとSpring Bootの変更から始まり、次にHibernateおよび関連技術のすべての変更について説明しました。最後に、Spring Data 3.0.1およびQuerydsl 5.0.0に関連する小さな変更について触れました。

上記で実演した完全なソースコードは私のGitHubリポジトリで利用可能です。

注: 同様のElasticsearchのアップグレードについても、Spring Boot 3を使用したSpring Data Elasticsearch 5.0へのアップグレードガイドという前の記事があります。

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