本エントリーはJava Advent Calendarの21日目です。昨日はHatanoさんの文鳥は家鴨の夢を見るか #Java - Qiitaでした。
OpenRewriteを使用して、MultiProject構成のSpringBoot2をSpringBoot3にマイグレーションを行います。所属している事業部ではよく用いられているSpringBoot x Gradle x マルチプロジェクト 構成に対して、マイグレーションを実施します。弊社でもOpenRewriteを使用してマイグレーションを行っています。
ディレクトリ
app
ディレクトリとservice
ディレクトリの2つのマルチプロジェクト構成になっています。
├── app │ ├── build │ ├── build.gradle │ └── src ├── build.gradle ├── gradlew ├── gradlew.bat ├── service │ ├── build │ ├── build.gradle │ └── src └── settings.gradle
build.gradle
build.gradleは、下記にようになっており、SpringBoot2.7.4
、Java17
となっています。
plugins { id 'java' id 'org.springframework.boot' version '2.7.4' apply false id 'io.spring.dependency-management' version '1.0.11.RELEASE' apply false } group = 'jp.co.excite' version = '0.0.1-SNAPSHOT' java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } subprojects { apply plugin: 'java' apply plugin: 'io.spring.dependency-management' apply plugin: 'org.springframework.boot' configurations { compileOnly { extendsFrom annotationProcessor } } repositories { mavenCentral() } dependencies { implementation 'org.springframework.boot:spring-boot-starter' implementation 'org.springframework.boot:spring-boot-starter-validation' compileOnly 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' annotationProcessor 'org.springframework.boot:spring-boot-configuration-processor' annotationProcessor 'org.projectlombok:lombok' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' } tasks.named('test') { useJUnitPlatform() } } project(":app") { dependencies { implementation project(":service") implementation 'org.springframework.boot:spring-boot-starter-web' } } project(":service") { repositories { mavenCentral() } }
コード
入力文字を大文字にするAPIを用意します。
コントローラは下記のようになります。
package jp.co.excite.adventcalendar.controller; import jp.co.excite.adventcalendar.SampleService; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; import javax.validation.constraints.NotBlank; @RestController @RequestMapping("/") public class RootController { private final SampleService sampleService; public RootController(SampleService sampleService) { this.sampleService = sampleService; } @RequestMapping("upper") public String upper(@NotBlank String text) { return sampleService.upper(text); } }
サービスは下記のようになります。
package jp.co.excite.adventcalendar; import org.springframework.stereotype.Service; public interface SampleService { String upper(String text); } @Service class SampleServiceImpl implements SampleService { @Override public String upper(String text) { return String.format("input: %s", text.toUpperCase()); } }
上記のAPIにOpenRewriteでマイグレーションをかけていきます。
build.gradleにOpenRewriteの設定を追加
OpenRewriteの設定を追加します。
マルチプロジェクト構成でも、rootproject
やsubprojects
のディレクティブの中に書くのではなく、トップ階層に書くのがポイントです。
plugins { id 'java' id 'org.springframework.boot' version '2.7.4' apply false id 'io.spring.dependency-management' version '1.0.11.RELEASE' apply false id 'org.openrewrite.rewrite' version '6.28.3' apply false // <-- 追加 } /* 下記を追加 */ java { toolchain { languageVersion = JavaLanguageVersion.of(17) } } apply plugin: 'org.openrewrite.rewrite' rewrite { activeRecipe("org.openrewrite.java.spring.boot3.UpgradeSpringBoot_3_3") activeRecipe("org.openrewrite.java.migrate.UpgradeToJava21") } repositories { mavenCentral() } dependencies { rewrite("org.openrewrite.recipe:rewrite-spring:5.25.0") rewrite("org.openrewrite.recipe:rewrite-migrate-java:2.31.0") } /* ここまで追加 */
今回は、SpringBoot3.3にするのに追加して、Java21にもアップデートします。
設定は、 rewrite
の中に適用するレシピを記述します。今回は、UpgradeSpringBoot_3_3
とUpgradeToJava21
を適用します。dependencies
には、それぞれの依存関係を書いておきます。
今回使用したレシピ以外にも、他の言語のものもあったりするので、探してみてください。
OpenRewriteを実行する
./gradlew rewriteDryRun // <-- コードは変更されません ./gradlew rewriteRun // <-- コードが変更されます
実行後の差分
キャプチャで見づらいかもですが、SpringBootのバージョン変更、java tool chain のバージョン変更、javax -> jakarta
パッケージの変更や、String.format -> "text".formatted
など変更されています。
まとめ
小さいサンプルコードなので変更は少ないですけど、実際は、2000ファイルや4000ファイルくらい変更がある場合もあります。そして、ほぼすぐ動作しますので単体テストを通して、ある程度負荷とテストとかして1週間もあればマイグレーションはできると思います。こういうツールが充実しているのはサービスを運営していく身としては大変助かります。